我怎么知道ExecutorService中的所有线程何时完成?

时间:2015-04-04 20:04:19

标签: java multithreading runnable executorservice

我知道shutdown()awaitTermination()存在。问题是池中的runnables需要能够向其添加一个未知数量(不能使用倒计时)其他runnables,如果我调用shutdown()那些任务将被拒绝。我怎么知道它们何时完成?

3 个答案:

答案 0 :(得分:1)

使用Future而不是Runnable。这种Future#isDone方法可以帮助您。

如果您没有从Callable返回任何有意义的内容,请使用Callable<Void>Future<Void>

答案 1 :(得分:0)

如果您能够使用Guava Futures,则可以使用Futures.allAsListFutures.successfulAsList。这允许您将从Future返回的许多ExecutorService个实例包装到单个Future中,然后您可以使用isDone()检查它是否已完成(或者只是get(),就此而言,如果你想阻止直到完成)。

答案 2 :(得分:0)

您应该使用ForkJoinTask / ForkJoinPool代替将Runnable任务提交给ExecutorForkJoinTaskForkJoinPool内运行,可以生成任意数量的(子)任务并等待它们完成,而不会实际阻塞当前线程。当ForkJoinTask完成所有子任务时,ForkJoinTask就完成了,所以当初始(根)Runnable完成时,整个计算就完成了。

有关详细信息,请参阅Oracle - The Java™ Tutorials - Fork/Join

由于您的所有任务都是无结果的(RecursiveAction),您应该将ForkJoinTask(它本身是compute()的子类)子类化。实施方法invoke(subtask),并通过调用invokeAll(subtask1, subtask2, ...)subtask.fork()subtask.join()后跟MyRecursiveAction task = new MyRecursiveAction(params); ForkJoinPool pool = new ForkJoinPool(numberOfThreads); pool.invoke(task); // will block until task is done 来生成任意数量的新任务。

整个计算执行如下:

{{1}}

不幸的是,Fork / Join的优点有一些限制,例如:

  

(...)理想情况下,计算应避免同步方法或块,以及   应尽量减少其他阻止同步,除了加入   其他任务或使用广告的Phasers等同步器   配合fork / join调度。也可以进行细分任务   不执行阻塞I / O,理想情况下应该访问变量   完全独立于其他正在运行的任务访问的那些。这些   不允许检查异常,松散地强制执行准则   例如要抛出的IOExceptions。 (...)

有关详细信息,请参阅API docs of ForkJoinTask