在下面的例子中,为什么两个异常都会传播到主线程?
(这是我配置为在调用stop()时抛出运行时异常的测试):
List<Future> futures = new ArrayList<>();
futures.add(executorService.submit(runnable1));
futures.add(executorService.submit(runnable2));
Thread.sleep(1000L); // wait for runnables to run for a while
runnable2.stop();
runnable1.stop();
for (Future future : futures) {
try {
future.get();
} catch(Exception e) {
System.out.println("Exception occurred");
}
}
我希望只有第一个被传播,因为第二个被吞下这个设置(因为它通过循环遍历数组列表顺序等待第一个runnable)。
如果我们只调用runnable2.stop(),就可以看到这种吞咽的一个例子 - 在这种情况下根本没有显示任何内容。
为什么会打印runnable2的例外?
我还应该提一下,当在每个线程上调用stop()时,在抛出异常以允许仍然调用期货循环之前,方法内部会有一个暂停。
答案 0 :(得分:1)
如果你只在第二个上调用stop()
,那么for
循环将永远等待第一个完成。这个例外没有被吞下;如果您的程序在第二个未来调用get()
,但是您的程序已经等待第一个未来,并且无法达到该点,那么它已被捕获并将被抛出。
答案 1 :(得分:0)
在下面的例子中,为什么两个异常都会传播到主线程?
这是Future
类的性质。它包装了你的工作,所以无论正在执行和完成的工作的顺序如何,它都会返回结果或在你致电future.get()
时抛出异常。
因此,如果第二个作业首先抛出异常,它将存储在与作业关联的Future
中,以便稍后通过futures
列表时可以返回,即使是第一个future.get()
可能需要等待第一份工作完成。
如果您愿意,可以查看FutureTask
的代码。以下是一些片段:
public void run() {
...
try {
// Gray: this calls your job, storing the result
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
// this puts ex into result and sets the state to EXCEPTIONAL
setException(ex);
}
然后:
public V get() throws InterruptedException, ExecutionException {
...
Object x = outcome;
if (s == NORMAL)
return (V)x;
if (s >= CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable)x);
因此,当运行结束时,call()
方法的结果或结果异常与outcome
一起存储在state
中,NORMAL
或{EXCEPTIONAL
1}}。