Java 异常向主线程的传播
在以下情况下,为什么两个异常都会传播到主线程 (这是一个测试,我已将其配置为在调用stop()时引发运行时异常):Java 异常向主线程的传播,java,multithreading,exception-handling,future,runnable,Java,Multithreading,Exception Handling,Future,Runnable,在以下情况下,为什么两个异常都会传播到主线程 (这是一个测试,我已将其配置为在调用stop()时引发运行时异常): List futures=new ArrayList(); futures.add(executorService.submit(runnable1)); futures.add(executorService.submit(runnable2)); 线程。睡眠(1000L);//等待runnables运行一段时间 runnable2.stop(); runnable1.stop(
List futures=new ArrayList();
futures.add(executorService.submit(runnable1));
futures.add(executorService.submit(runnable2));
线程。睡眠(1000L);//等待runnables运行一段时间
runnable2.stop();
runnable1.stop();
for(未来:未来){
试一试{
future.get();
}捕获(例外e){
System.out.println(“发生异常”);
}
}
我希望只有第一个会被传播,因为第二个会被这个设置吞没(因为它通过按顺序循环遍历数组列表来等待第一个runnable)
如果我们只调用runnable2.stop(),就可以看到这种吞咽的例子——在这种情况下,根本没有显示任何内容
为什么会打印runnable2的例外
我还应该提到,当在每个线程上调用stop()时,方法内部会有一个暂停,然后抛出异常,以允许继续调用futures循环。如果只在第二个线程上调用
stop()
,那么for
循环将永远等待第一个线程完成。例外没有被吞没;它已被捕获,并且当您的程序在第二个将来调用get()
时将抛出,但您的程序已挂起等待第一个将来,并且不会到达该点
在以下情况下,为什么两个异常都会传播到主线程
这就是未来类的本质。它包装您的作业,因此无论执行和完成作业的顺序如何,当您调用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);
}
然后:
因此,当运行完成call()
方法的结果或产生的异常与NORMAL
或exception状态一起存储在output
中时,我不明白为什么在到达循环时第二个异常不会被清除,两项任务都已完成。那么你为什么期望一个被吞下呢?@MauricePerry,因为循环的性质,我们正在等待runnable1首先完成。如果使用此设置仅在第二个线程上调用stop,则不会显示任何内容。如果我对第一个线程执行相同的操作,我们会看到一个异常,它会在第二个线程上开始等待。但是在这里,您同时停止了这两个线程。所以这两个测试都已完成,所以不需要等待。@realponsign抱歉,我没有提到此测试配置为在完成之前调用stop()时在每个线程中暂停。测试一下,你会发现同样的行为。
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);