“由于故障导致的线程终止”是指什么?
ExecutorService
的javadoc有时指的是Thread因“失败”而终止的情况。 但是,目前尚不清楚这是指什么样的失败。
例如, 单线程执行程序文档说明了这一点
如果由于在关闭之前执行期间的故障而导致该单个线程终止,则如果需要执行后续任务,则新线程将取代它
我原以为这种情况可能发生在Exception或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指的是什么样的“失败”?
这是个有趣的问题。 在ThreadPoolExecutor
的代码之后,当Runnable
传递给execute()
方法时,线程被丢弃。
当您调用submit()
,执行程序为FutureTask
类型的可调用/可运行创建一个包装器。 FutureTask.run()
有一些逻辑来捕获exception并存储它们(所以,你可以从Future
查询它)。 在这种情况下,exception永远不会到达ThreadPool
,因此不会丢弃该线程。
奥古斯托是对的。 Runnable
任务应该在遇到exception时丢弃线程,因为它们在execute()
方法中作为参数传递。
我已经在本文和Future Task源代码中找到了有关吞噬未来任务exception的具体证据
**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中有一些更有趣的问题。
从Java ExecutorService捕获线程exception
在ExecutorService的提交和ExecutorService的执行之间进行选择
编辑:
当线程代码中未捕获exception时,将发生线程故障或终止。 如果通过execute()
而不是submit()
提交任务,则除非捕获exception,否则不会捕获exception。 线程代码未捕获的exception将导致线程终止或失败,并且Executor将创建新线程 。
如果通过submit(),
提交任务submit(),
将创建FutureTask
,该任务将吞下未捕获的exception代码。 由于exception是在FutureTask
中捕获的,因此不会丢弃该线程。