簡體   English   中英

如何等待 ThreadPoolExecutor 完成

[英]How to wait for a ThreadPoolExecutor to finish

我的問題:如何在ThreadPoolExecutor上執行一堆線程對象並等待它們全部完成后再繼續?

我是 ThreadPoolExecutor 的新手。 所以這段代碼是一個測試,以了解它是如何工作的。 現在我什至沒有用對象填充BlockingQueue因為我不明白如何在不使用另一個RunnableObject調用execute()情況下啟動隊列。 無論如何,現在我只是調用awaitTermination()但我想我仍然缺少一些東西。 任何提示都會很棒! 謝謝。

public void testThreadPoolExecutor() throws InterruptedException {
  int limit = 20;
  BlockingQueue q = new ArrayBlockingQueue(limit);
  ThreadPoolExecutor ex = new ThreadPoolExecutor(limit, limit, 20, TimeUnit.SECONDS, q);
  for (int i = 0; i < limit; i++) {
    ex.execute(new RunnableObject(i + 1));
  }
  ex.awaitTermination(2, TimeUnit.SECONDS);
  System.out.println("finished");
}

RunnableObject 類:

package playground;

public class RunnableObject implements Runnable {

  private final int id;

  public RunnableObject(int id) {
    this.id = id;
  }

  @Override
  public void run() {
    System.out.println("ID: " + id + " started");
    try {
      Thread.sleep(2354);
    } catch (InterruptedException ignore) {
    }
    System.out.println("ID: " + id + " ended");
  }
}

你應該循環awaitTermination

ExecutorService threads;
// ...
// Tell threads to finish off.
threads.shutdown();
// Wait for everything to finish.
while (!threads.awaitTermination(10, TimeUnit.SECONDS)) {
  log.info("Awaiting completion of threads.");
}

您的問題似乎是在將所有作業提交到池后沒有調用shutdown 如果沒有shutdown()您的awaitTermination將始終返回 false。

ThreadPoolExecutor ex =
    new ThreadPoolExecutor(limit, limit, 20, TimeUnit.SECONDS, q);
for (int i = 0; i < limit; i++) {
  ex.execute(new RunnableObject(i + 1));
}
// you are missing this line!!
ex.shutdown();
ex.awaitTermination(2, TimeUnit.SECONDS);

您還可以執行以下操作以等待所有作業完成:

List<Future<Object>> futures = new ArrayList<Future<Object>>();
for (int i = 0; i < limit; i++) {
  futures.add(ex.submit(new RunnableObject(i + 1), (Object)null));
}
for (Future<Object> future : futures) {
   // this joins with the submitted job
   future.get();
}
...
// still need to shutdown at the end
ex.shutdown();

此外,因為您睡眠了2354毫秒,但只等待所有作業終止2 SECONDSawaitTermination將始終返回false 我會使用Long.MAX_VALUE來等待作業完成。

最后,聽起來您擔心創建一個新的ThreadPoolExecutor而您想要重用第一個。 別這樣與您為檢測作業是否完成而編寫的任何代碼相比,GC 開銷將非常小。


引用 javadocs 中的ThreadPoolExecutor.shutdown()

啟動有序關閉,其中執行先前提交的任務,但不會接受新任務。 如果已經關閉,調用沒有額外的效果。

ThreadPoolExecutor.awaitTermination(...)方法中,它正在等待執行器的狀態轉到TERMINATED 但首先,國家必須去SHUTDOWN如果shutdown()被調用或STOP如果shutdownNow()被調用。

這與執行者本身無關。 只需使用接口的java.util.concurrent.ExecutorService.invokeAll(Collection<? extends Callable<T>>) 它將阻塞,直到所有Callable完成。

Executors 應該是長壽的; 超出一組任務的生命周期。 shutdown用於應用程序完成並清理時。

這是已接受的答案的一個變體,它在拋出 InterruptedException 時處理重試:

executor.shutdown();

boolean isWait = true;

while (isWait)
{
    try
    {             
        isWait = !executor.awaitTermination(10, TimeUnit.SECONDS);
        if (isWait)
        {
            log.info("Awaiting completion of bulk callback threads.");
        }
    } catch (InterruptedException e) {
        log.debug("Interruped while awaiting completion of callback threads - trying again...");
    }
}

另一種方法是使用 CompletionService,如果您必須嘗試任何任務結果,這將非常有用:

//run 3 task at time
final int numParallelThreads = 3;

//I used newFixedThreadPool for convenience but if you need you can use ThreadPoolExecutor
ExecutorService executor = Executors.newFixedThreadPool(numParallelThreads);
CompletionService<String> completionService = new ExecutorCompletionService<String>(executor);

int numTaskToStart = 15;

for(int i=0; i<numTaskToStart ; i++){
    //task class that implements Callable<String> (or something you need)
    MyTask mt = new MyTask();

    completionService.submit(mt);
}

executor.shutdown(); //it cannot be queued more task

try {
    for (int t = 0; t < numTaskToStart ; t++) {
        Future<String> f = completionService.take();
        String result = f.get();
        // ... something to do ...
    }
} catch (InterruptedException e) {
    //termination of all started tasks (it returns all not started tasks in queue)
    executor.shutdownNow();
} catch (ExecutionException e) {
    // ... something to catch ...
}

試試這個,

ThreadPoolExecutor ex =
    new ThreadPoolExecutor(limit, limit, 20, TimeUnit.SECONDS, q);
for (int i = 0; i < limit; i++) {
  ex.execute(new RunnableObject(i + 1));
}

要添加的行

ex.shutdown();
ex.awaitTermination(timeout, unit)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM