ExecutorService,如何等待所有任务完成

243

等待 ExecutorService 的所有任务完成的最简单方法是什么?我的任务主要是计算型的,所以我只想在每个核心上运行大量的作业。目前我的设置如下:

ExecutorService es = Executors.newFixedThreadPool(2);
for (DataTable singleTable : uniquePhrases) {   
    es.execute(new ComputeDTask(singleTable));
}
try{
    es.wait();
} 
catch (InterruptedException e){
    e.printStackTrace();
}

ComputeDTask 实现了可运行接口。代码似乎可以正确执行任务,但是在 wait() 上会崩溃,并出现 IllegalMonitorStateException。这很奇怪,因为我玩弄一些玩具例子,它似乎可以工作。

uniquePhrases 包含几万个元素。我应该使用另一种方法吗?我正在寻找尽可能简单的解决方案。

16个回答

2
将集合中的所有线程添加并使用invokeAll提交。 如果您可以使用ExecutorServiceinvokeAll方法,JVM将在所有线程完成之前不会继续执行下一行代码。
这里有一个很好的例子:通过ExecutorService调用invokeAll

1
将您的任务提交到Runner中,然后等待调用方法waitTillDone(),如下所示:
Runner runner = Runner.runner(2);

for (DataTable singleTable : uniquePhrases) {

    runner.run(new ComputeDTask(singleTable));
}

// blocks until all tasks are finished (or failed)
runner.waitTillDone();

runner.shutdown();

要使用它,请添加此gradle/maven依赖项:'com.github.matejtymes:javafixes:1.0'

有关更多详细信息,请查看此处:https://github.com/MatejTymes/JavaFixes 或此处:http://matejtymes.blogspot.com/2016/04/executor-that-notifies-you-when-task.html


0
听起来你需要 ForkJoinPool 并使用全局池来执行任务。
public static void main(String[] args) {
    // the default `commonPool` should be sufficient for many cases.
    ForkJoinPool pool = ForkJoinPool.commonPool(); 
    // The root of your task that may spawn other tasks. 
    // Make sure it submits the additional tasks to the same executor that it is in.
    Runnable rootTask = new YourTask(pool); 
    pool.execute(rootTask);
    pool.awaitQuiescence(...);
    // that's it.
}

美妙之处在于pool.awaitQuiescence,该方法将阻塞利用调用者的线程来执行其任务,然后在它真正为空时返回。


0

这个怎么样?

Object lock = new Object();
CountDownLatch cdl = new CountDownLatch(threadNum);
for (int i = 0; i < threadNum; i++) {
    executorService.execute(() -> {

        synchronized (lock) {
            cdl.countDown();
            try {
                lock.wait();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    });
}
cdl.await();
synchronized (lock) {
    lock.notifyAll();
}

如果您不向ExecutorService添加新任务,则可能会等待所有当前任务完成。

0

我将等待执行器在指定的超时时间内终止,您认为这适合任务完成。

 try {  
         //do stuff here 
         exe.execute(thread);
    } finally {
        exe.shutdown();
    }
    boolean result = exe.awaitTermination(4, TimeUnit.HOURS);
    if (!result)

    {
        LOGGER.error("It took more than 4 hour for the executor to stop, this shouldn't be the normal behaviour.");
    }

-1
一个简单的替代方法是使用线程和join。 参考:加入线程

4
ExecutorServices让事情变得更简单。 - David Mann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接