由于失败导致线程终止的原因是什么?参考?

时间:2015-11-15 21:11:01

标签: java multithreading executorservice

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指的是什么?

2 个答案:

答案 0 :(得分:3)

这是一个有趣的问题。在ThreadPoolExecutor中的代码之后,当Runnable传递给execute()时,线程将被丢弃。

当您调用submit()时,执行程序为类型为FutureTask的可调用/可运行创建包装器。 FutureTask.run()有一些逻辑来捕获异常并存储它们(因此,您可以从Future查询)。在这种情况下,异常永远不会到达ThreadPool,因此不会丢弃该线程。

答案 1 :(得分:0)

奥古斯托是对的。 Runnable任务在execute()方法中作为参数传递后遇到异常后应该丢弃线程。

我已经在articleFuture 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中捕获的,因此线程不会被丢弃。