web-dev-qa-db-ja.com

ExecutorServiceで実行されているすべてのタスクが完了したかどうかを確認する方法

同期プッシュ/ポップ要素に使用しているConcurrentLinkedDequeがあり、スタックから1つの要素を取得し、この要素に隣接要素がある場合、それをスタックにプッシュする非同期タスクがあります。

サンプルコード:

private ConcurrentLinkedDeque<Item> stack = new ConcurrentLinkedDeque<>();
private ExecutorService exec = Executors.newFixedThreadPool(5);

    while ((item = stack.pollFirst()) != null) {
                if (item == null) {
                } else {
                    Runnable worker = new Solider(this, item);
                    exec.execute(worker);
                }
            }

   class Solider{
         public void run(){
             if(item.hasNeighbors){
                for(Item item:item.neighbors){
                    stack.Push(item)
                }
             } 
         }
    }

「Executorのタスクが機能していますか?」という質問に答えるwhileループに追加のステートメントが必要です。

24
user4129715

ExecutorService.execute(Runnable)を使用する場合、すべてのRunnableが完了したかどうかを確認する明確な方法はありません。 Runnable自体でそうするためのメカニズムを構築しない限り(私の意見ではだらしない)。

代わりに:
ExecutorService.submit(Runnable)を使用します。このメソッドは、Runnableの結果のハンドルであるFuture<?>を返します。 Futuresを使用すると、結果を確認するためのクリーンな方法が提供されます。

あなたがしなければならないことは、あなたが提出する先物のリストを維持することです、そして、あなたは先物のリスト全体を反復できます:
A)すべての先物が妨害的な方法で行われるのを待つか、
B)すべての先物が非ブロッキング方式で実行されているかどうかを確認します。

コード例を次に示します。

List<Future<?>> futures = new ArrayList<Future<?>>();
ExecutorService exec = Executors.newFixedThreadPool(5);

// Instead of using exec.execute() use exec.submit()
// because it returns a monitorable future
while((item = stack.pollFirst()) != null){
    Runnable worker = new Solider(this, item);
    Future<?> f = exec.submit(worker);
    futures.add(f);
}

// A) Await all runnables to be done (blocking)
for(Future<?> future : futures)
    future.get(); // get will block until the future is done

// B) Check if all runnables are done (non-blocking)
boolean allDone = true;
for(Future<?> future : futures){
    allDone &= future.isDone(); // check if future is done
}
54
Andy Guibert