ExecutorService
的javadoc有时指的是线程因故障而终止的情况'。但是,目前尚不清楚这是指什么样的失败。
例如,single thread executor文档说明了
如果此单个线程由于执行期间的失败而终止 在关闭之前,如果需要执行,新的将取代它 后续任务
我原本以为这种情况可能发生在异常情况下,或者可能是RuntimeException
,但似乎并非如此。运行以下代码似乎给出了相同的线程名称和线程ID。
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> {
System.out.println("Hello from " + Thread.currentThread().getName()+ " " + Thread.currentThread().getId());
throw new NullPointerException("Test");
});
executor.submit(() -> {
System.out.println("Hello 2 from " + Thread.currentThread().getName() + " " + Thread.currentThread().getId());
});
此代码的输出为:
Hello from pool-1-thread-1 12
Hello 2 from pool-1-thread-1 12
即使在NullPointerException
的情况下,似乎也在重用相同的线程。
那是什么样的失败'是Javadoc指的是什么?
答案 0 :(得分:3)
这是一个有趣的问题。在ThreadPoolExecutor
中的代码之后,当Runnable
传递给execute()
时,线程将被丢弃。
当您调用submit()
时,执行程序为类型为FutureTask
的可调用/可运行创建包装器。 FutureTask.run()
有一些逻辑来捕获异常并存储它们(因此,您可以从Future
查询)。在这种情况下,异常永远不会到达ThreadPool
,因此不会丢弃该线程。
答案 1 :(得分:0)
奥古斯托是对的。 Runnable
任务在execute()
方法中作为参数传递后遇到异常后应该丢弃线程。
我已经在article和Future Task source code
找到了有关未来任务吞下例外情况的具体证据**Inside FutureTask$Sync**
void innerRun() {
if (!compareAndSetState(READY, RUNNING))
return;
runner = Thread.currentThread();
if (getState() == RUNNING) { // recheck after setting thread
V result;
try {
result = callable.call();
} catch (Throwable ex) {
setException(ex);
return;
}
set(result);
} else {
releaseShared(0); // cancel
}
}
protected void setException(Throwable t) {
sync.innerSetException(t);
}
关于这个主题,SE中还有一些有趣的问题。
Catching thread exceptions from Java ExecutorService
Choose between ExecutorService's submit and ExecutorService's execute
修改强>
当线程代码中未捕获异常时,将发生线程故障或终止。如果您按execute()
而不是submit()
提交任务,则除非您发现异常,否则将无法捕获异常。 线程代码的未捕获异常将导致线程终止或失败,并且Executor将创建新线程。
如果您通过submit(),
提交任务,则会创建FutureTask
,该任务将吞没未捕获的代码异常。由于异常是在FutureTask
中捕获的,因此线程不会被丢弃。