Что означает "Завершение потока из-за сбоя"?
Javadoc для ExecutorService
иногда относится к случаю, когда поток завершается "из-за сбоя". Тем не менее, не ясно, к какому типу ошибок это относится.
Например, в документации по исполнителю из одного потока сказано, что
если этот единственный поток завершается из-за сбоя во время выполнения до выключения, новый будет занимать его место, если это необходимо для выполнения последующих задач
Я бы подумал, что эта ситуация может произойти в случае исключения, или, возможно, RuntimeException
, но, похоже, это не так. Запуск следующего кода, похоже, дает одинаковое имя потока и идентификатор потока.
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 ответа
Это интересный вопрос. После кода в ThreadPoolExecutor
поток отбрасывается, когда Runnable
передается в execute()
метод.
Когда вы звоните submit()
исполнитель создает оболочку для вызываемого / запускаемого типа FutureTask
, FutureTask.run()
имеет некоторую логику, чтобы перехватывать исключения и хранить их (так что вы можете запросить это из Future
). В этом случае исключение никогда не достигает ThreadPool
, так что нить не отбрасывается.
Аугусто прав. Runnable
задачи должны были отбросить поток после возникновения исключения, когда они были переданы в качестве параметра в execute()
метод.
В этой статье и исходном коде Future Task я нашел конкретные доказательства проглатывания исключений задачами Future.
**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
Выберите между отправкой ExecutorService и выполнением ExecutorService
РЕДАКТИРОВАТЬ:
Сбой или завершение потока произойдет, когда исключение не будет обработано в коде потока. Если вы отправите задание по execute()
вместо submit()
исключение не будет поймано, пока вы не поймаете исключение. Неопределенное исключение по коду потока приведет к тому, что поток прекратится или произойдет сбой, и Executor создаст новый поток.
Если вы отправите задание через submit(),
FutureTask
будет создан, и эта задача будет проглотить необработанное исключение кодом. Поскольку исключение было поймано в FutureTask
поток не будет удален.