奇怪的异常传播到主线程
Curious exception propagation to main thread
在下面的例子中,为什么两个异常都会传播到主线程?
(这是我配置为在调用 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");
}
}
我希望只有第一个被传播,因为第二个被这个设置吞没了(因为它通过按顺序遍历数组列表等待第一个可运行的)。
如果我们只调用 runnable2.stop() 就可以看到这种吞咽的例子——在这种情况下根本没有任何显示。
为什么会打印 runnable2 的异常?
我还应该提到,当在每个线程上调用 stop() 时,方法内部会在抛出异常之前暂停,以允许仍调用 futures 循环。
如果您只在第二个上调用 stop()
,那么 for
循环将永远等待第一个完成。异常没有被吞噬;它已被捕获,如果您的程序在第二个未来调用 get()
时将被抛出,但您的程序已挂起等待第一个未来并且不会到达那个点。
In the following case, why is it that both exceptions get propagated to the main thread?
这就是Future
class的本质。它包装您的作业,因此无论作业执行和完成的顺序如何,它都会 return 结果或在您调用 future.get()
.
时抛出异常
因此,如果第二个作业首先抛出异常,它会存储在与该作业关联的 Future
中,因此当您浏览 futures
列表时可以对其进行 returned稍后,即使第一个 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()
方法的结果或由此产生的异常与 state
一起存储在 outcome
中,后者可以是 NORMAL
或 EXCEPTIONAL
.
在下面的例子中,为什么两个异常都会传播到主线程?
(这是我配置为在调用 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");
}
}
我希望只有第一个被传播,因为第二个被这个设置吞没了(因为它通过按顺序遍历数组列表等待第一个可运行的)。
如果我们只调用 runnable2.stop() 就可以看到这种吞咽的例子——在这种情况下根本没有任何显示。
为什么会打印 runnable2 的异常?
我还应该提到,当在每个线程上调用 stop() 时,方法内部会在抛出异常之前暂停,以允许仍调用 futures 循环。
如果您只在第二个上调用 stop()
,那么 for
循环将永远等待第一个完成。异常没有被吞噬;它已被捕获,如果您的程序在第二个未来调用 get()
时将被抛出,但您的程序已挂起等待第一个未来并且不会到达那个点。
In the following case, why is it that both exceptions get propagated to the main thread?
这就是Future
class的本质。它包装您的作业,因此无论作业执行和完成的顺序如何,它都会 return 结果或在您调用 future.get()
.
因此,如果第二个作业首先抛出异常,它会存储在与该作业关联的 Future
中,因此当您浏览 futures
列表时可以对其进行 returned稍后,即使第一个 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()
方法的结果或由此产生的异常与 state
一起存储在 outcome
中,后者可以是 NORMAL
或 EXCEPTIONAL
.