Что означает "Завершение потока из-за сбоя"?

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 поток не будет удален.

Другие вопросы по тегам