スレッドプールでのタスクの終了について

スレッド プール自体を使用してタスクを削除または終了するには、必要な前提条件があります。
タスクが queue に存在する必要があります

なぜそう言うのですか?

これは、いわゆる「削除タスク」が ThreadPoolExecutor の remove メソッドを参照しているためです。

    public boolean remove(Runnable task) {
    
    
        boolean removed = workQueue.remove(task);
        tryTerminate(); // In case SHUTDOWN and now empty
        return removed;
    }

ご覧のとおり、これをworkQueueから削除する必要があります
。つまり、タスクが既に実行されている場合、スレッド プールを使用して削除することは理論的に不可能です。

例えば:

	private static void testNormalRemove() {
    
    
		ThreadPoolExecutor tpe = new ThreadPoolExecutor(1, 3, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>(3));

		Thread task1 = new Thread(new Runnable() {
    
    
			@Override
			public void run() {
    
    
					while (true) {
    
    
						try {
    
    
							TimeUnit.SECONDS.sleep(2);
						} catch (InterruptedException e) {
    
    
							e.printStackTrace();
						}
						System.out.println("normal1," + Thread.currentThread().getId());
					}
				}
		});
		Thread task2 = new Thread(new Runnable() {
    
    
			@Override
			public void run() {
    
    
				while (true) {
    
    
					try {
    
    
						TimeUnit.SECONDS.sleep(3);
					} catch (InterruptedException e) {
    
    
						e.printStackTrace();
						return;
					}
					System.out.println("normal2," + Thread.currentThread().getId());
				}
			}
		});
		tpe.execute(task1);
		tpe.execute(task2);

		try {
    
    
			TimeUnit.SECONDS.sleep(6);
		} catch (InterruptedException e) {
    
    
			e.printStackTrace();
		}
		System.out.println(tpe.getQueue().size());
		System.out.println("remove task2," + tpe.remove(task2));

		try {
    
    
			TimeUnit.SECONDS.sleep(6);
		} catch (InterruptedException e) {
    
    
			e.printStackTrace();
		}

	}

task1 と task2 の 2 つのタスクがあり、作成されたスレッド プールのコア スレッドが 1 である場合、task1 は追加された直後に実行され、task2 はキューに追加されて実行を待機します。スレッドプールの原則、その後、タスク2は正常に削除されましたが、タスク1はキューにまったくないため削除できません.

もちろん、いくつかの特別なスレッド プールがあり、各タスクが実際にキューに追加されます。たとえば、ScheduledThreadPoolExecutor がタスクを追加すると、各タスクが実際にキューに追加されます。

    public void execute(Runnable command) {
    
    
        schedule(command, 0, NANOSECONDS);
    }

    public ScheduledFuture<?> schedule(Runnable command,
                                       long delay,
                                       TimeUnit unit) {
    
    
        if (command == null || unit == null)
            throw new NullPointerException();
        RunnableScheduledFuture<?> t = decorateTask(command,
            new ScheduledFutureTask<Void>(command, null,
                                          triggerTime(delay, unit)));
        delayedExecute(t);
        return t;
    }

    private void delayedExecute(RunnableScheduledFuture<?> task) {
    
    
        if (isShutdown())
            reject(task);
        else {
    
    
            super.getQueue().add(task);
            if (isShutdown() &&
                !canRunInCurrentRunState(task.isPeriodic()) &&
                remove(task))
                task.cancel(false);
            else
                ensurePrestart();
        }
    }

この方法で追加されたタスクは削除できます.
もちろん, 追加されたタスクはRunnableScheduledFutureにカプセル化されていることに注意してください. 削除するときは, 削除する前に RunnableScheduledFuture に変換することを忘れないでください. RunnableScheduledFuture を直接、戻り値を削除できます。

他のスレッド プールはそれほど「ラッキー」ではありません. 一般的な規則に従って, それらは corePoolSize を超えた場合にのみキューに参加します. スレッド プール内のスレッドを停止する方法があります. しかし, スレッド プール内のスケジューリング方法のほとんど
はプライベートであり、次のように呼び出すことはできません。

    private void processWorkerExit(Worker w, boolean completedAbruptly) {
    
    
        if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
            decrementWorkerCount();

        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
    
    
            completedTaskCount += w.completedTasks;
            workers.remove(w);
        } finally {
    
    
            mainLock.unlock();
        }
		//略
    }

すでに実行中のスレッドまたはタスクは Worker としてカプセル化されますが、Worker のメソッドは外部に公開されません。そのため、ほとんどのスレッド プールはスレッドを細かく制御できません。もちろん、スレッド自体は非常にきめ細かく制御されます。

一般的に、一度スレッドを起動すると、従来の方法では停止することが難しく、例外をスローしたり、リターンを追加したり、割り込みを強制的に停止させたりする必要がある場合が多い; これらのシーンも良い選択です
.

おすすめ

転載: blog.csdn.net/ifmylove2011/article/details/105792099