简体   繁体   English

如何等待 ThreadPoolExecutor 完成

[英]How to wait for a ThreadPoolExecutor to finish

My Question: How to execute a bunch of threaded objects on a ThreadPoolExecutor and wait for them all to finish before moving on?我的问题:如何在ThreadPoolExecutor上执行一堆线程对象并等待它们全部完成后再继续?

I'm new to ThreadPoolExecutor.我是 ThreadPoolExecutor 的新手。 So this code is a test to learn how it works.所以这段代码是一个测试,以了解它是如何工作的。 Right now I don't even fill the BlockingQueue with the objects because I don't understand how to start the queue without calling execute() with another RunnableObject .现在我什至没有用对象填充BlockingQueue因为我不明白如何在不使用另一个RunnableObject调用execute()情况下启动队列。 Anyway, right now I just call awaitTermination() but I think I'm still missing something.无论如何,现在我只是调用awaitTermination()但我想我仍然缺少一些东西。 Any tips would be great!任何提示都会很棒! Thanks.谢谢。

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");
}

The RunnableObject class: 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");
  }
}

You should loop on awaitTermination你应该循环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.");
}

Your issue seems to be that you are not calling shutdown after you have submitted all of the jobs to your pool.您的问题似乎是在将所有作业提交到池后没有调用shutdown Without shutdown() your awaitTermination will always return false.如果没有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);

You can also do something like the following to wait for all your jobs to finish:您还可以执行以下操作以等待所有作业完成:

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();

Also, because you are sleeping for 2354 milliseconds but only waiting for the termination of all of the jobs for 2 SECONDS , awaitTermination will always return false .此外,因为您睡眠了2354毫秒,但只等待所有作业终止2 SECONDSawaitTermination将始终返回false I would use Long.MAX_VALUE to wait for the jobs to finish.我会使用Long.MAX_VALUE来等待作业完成。

Lastly, it sounds like you are worrying about created a new ThreadPoolExecutor and you instead want to reuse the first one.最后,听起来您担心创建一个新的ThreadPoolExecutor而您想要重用第一个。 Don't be.别这样The GC overhead is going to be extremely minimal compared to any code that you write to detect if the jobs are finished.与您为检测作业是否完成而编写的任何代码相比,GC 开销将非常小。


To quote from the javadocs, ThreadPoolExecutor.shutdown() :引用 javadocs 中的ThreadPoolExecutor.shutdown()

Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted.启动有序关闭,其中执行先前提交的任务,但不会接受新任务。 Invocation has no additional effect if already shut down.如果已经关闭,调用没有额外的效果。

In the ThreadPoolExecutor.awaitTermination(...) method, it is waiting for the state of the executor to go to TERMINATED .ThreadPoolExecutor.awaitTermination(...)方法中,它正在等待执行器的状态转到TERMINATED But first the state must go to SHUTDOWN if shutdown() is called or STOP if shutdownNow() is called.但首先,国家必须去SHUTDOWN如果shutdown()被调用或STOP如果shutdownNow()被调用。

It's nothing to do with the executor itself.这与执行者本身无关。 Just use the interface's java.util.concurrent.ExecutorService.invokeAll(Collection<? extends Callable<T>>) .只需使用接口的java.util.concurrent.ExecutorService.invokeAll(Collection<? extends Callable<T>>) It will block until all the Callable s are finished.它将阻塞,直到所有Callable完成。

Executors are meant to be long-lived; Executors 应该是长寿的; beyond the lifetime of a group of tasks.超出一组任务的生命周期。 shutdown is for when the application is finished and cleaning up. shutdown用于应用程序完成并清理时。

Here's a variant on the accepted answer that handles retries if/when InterruptedException is thrown:这是已接受的答案的一个变体,它在抛出 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...");
    }
}

Another approach is to use CompletionService, very useful if you have to attempt any task result:另一种方法是使用 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 ...
}

Try this,试试这个,

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

Lines to be added要添加的行

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM