【发布时间】:2015-09-30 12:04:53
【问题描述】:
我目前的代码如下所示:
public void doThings() {
int numThreads = 4;
ExecutorService threadPool = Executors.newFixedThreadPool(numThreads);
for (int i = 0; i < numThreads; i++) {
final int index = i;
Runnable runnable = () -> {
// do things based on index
};
threadPool.execute(runnable);
}
threadPool.shutdown();
try {
// I'd like to catch exceptions here from any of the runnables
threadPool.awaitTermination(1, TimeUnit.HOURS);
} catch (InterruptedException e) {
Utils.throwRuntimeInterruptedException(e);
}
}
基本上,我会并行创建很多工作,然后等待全部完成。如果任何处理失败,我需要快速知道并中止这一切。 threadPool.awaitTermination 似乎没有注意到是否在其中一个线程内引发了异常。我只是在控制台中看到一个堆栈跟踪。
我对并发了解不多,所以我对所有可用的接口/对象有点迷失,例如Callable、Future、Task 等。
我看到threadPool.invokeAll(callables) 会给我一个List<Future> 和Future.get() 可以从线程内抛出异常,但是如果我调用它(如果可调用对象在它自己的线程中抛出异常)。但是,如果我 .get 在顺序集合中拥有每个可调用对象,那么在所有其他对象都完成之前,我不会知道最后一个对象是否失败。
我最好的猜测是有一个队列,可运行对象在其上放置 Boolean 表示成功或失败,然后将 take() 从队列中放入与线程数一样多的次数。
对于一个看似非常常见、简单的用例,我觉得这太复杂了(即使只是我粘贴的代码也有点长得惊人)。这甚至不包括在失败时中止可运行文件。必须有更好的方法,作为初学者我不知道。
【问题讨论】:
-
可以使用
shutdownNow()方法停止所有线程。当其中一个操作失败时调用此方法。 -
谢谢,这会有所帮助。我想我应该确保每个可运行对象都定期运行
if (Thread.currentThread().isInterrupted()) throw new RuntimeException();? -
只有在使用 Callable 时才可能出现异常。对于 Runnable,return 语句应该足够了吗?
-
@Johannes 否,因为我要检查中断的地方在深处,而不是直接在
run方法中。 -
您可以使用共享的“errorFlag”并中止操作(如果已设置)。这是关于向其他线程发出信号的部分。当然,您必须定期检查它,但无论如何必须同样支持中断。要设置它,您可以在
run中使用一个大的try/catch 包围您的所有代码,在catch 中设置errorFlag。这就是我要做的。
标签: java multithreading exception-handling future executorservice