Java Thread: метод Run не может выставить проверенное исключение

В потоке Java метод "run" не может выставить "проверенное исключение". Я наткнулся на это в книге Core Java (vol 1). Может кто-нибудь объяснить причины этого?

Ответы

Ответ 1

Может кто-нибудь объяснить причину этого?

Да, потому что любое исключение, которое вы выбрали методом run, будет тщательно проигнорировано JVM. Таким образом, бросать его там, вероятно, является ошибкой (если у вас нет конкретного обработчика исключений для потока, см. docs об этом). Нет причин побуждать потенциально ошибочное поведение.

Или с примером.

 class MyThread extends Thread {
     public void run() {
         throw new RuntimeException();
     }
 }

...

new MyThread().start();
// here thread dies silently with no visible effects at all

изменить

Почему родительский поток не может "уловить" исключение из порожденного "дочернего" потока?

@chaotic3quilibrium уже отметил в своем комментарии, почему бы и нет: поскольку родительский поток, вероятно, уже продвинулся.

new MyThread().start(); // launch thread and forget

// 1000 lines of code further...
i = i + 1; // would you like exception from child thread to be propagated here?

Ответ 2

Что бы поймать исключение и обработать его? Предположим, что метод run может выставить проверенное исключение. Затем вы можете написать код следующим образом:

Thread myThread = new Thread(aRunnable);
try{
    myThread.start();
}
catch(Exception e){
   e.printStackTrace();
}
//do other stuff

НО, как только вы вызываете myThread.start, новый поток запускается в фоновом режиме, и текущий поток продолжается и выходит из try-catch и выполняет другие действия. Поэтому, если myThread сделал исключение позже, вы не сможете его поймать!

Что вам нужно сделать, это обработать исключение в методе run, а затем, возможно, иметь способ уведомить другой объект, который этот поток не удалось.

Ответ 3

Предположим, что поток A запускает поток B. Затем поток B выдает исключение. Вы могли бы подумать, что было бы хорошо, если бы поток A поймал его. Но где? К тому времени, когда поток B исключает, кто знает, что делает поток A? Чтобы принять тривиальный пример, предположим, что у нас есть этот код в потоке A:

try
{
  threadB=new PurgeAbandonedCarts();
  threadB.start();
}
catch (NullPointerException panic)
{
  ... handle errors purging abandoned carts ...
}
try
{
  processNewOrders();
}
catch (NullPointerException panic)
{
  ... handle problems in new orders ...
}
finally
{
  ... clean up ...
}

Итак, мы запускаем нить B, чтобы очистить заброшенные тележки. Как только он начнется, мы перейдем к обработке новых заказов. Затем поток B выбрасывает исключение нулевого указателя. Должен ли он быть захвачен блоком catch, связанным с потоком B, или тем, который связан с обработкой новых заказов?

Если он идет на улов новых заказов, вероятно, что любой код здесь не имеет ничего общего с очисткой проблем с потоком B. Это не может быть правильным ответом.

Если вы говорите тот, который связан с потоком B, то это означает, что во время обработки новых заказов управление может внезапно выворачиваться и отправляться обратно, чтобы попробовать блок catch catch B. Но что случилось с обработкой новых заказов? Мы просто остановимся посередине? Мы даже не попали в блок finally? И когда мы закончим, мы просто продолжаем выполнять и проваливаться для обработки новых заказов снова? Мы обрабатываем заказы дважды? Это тоже не может быть правильным ответом.

Таким образом, некуда идти, если run вызывает исключение. Единственное, что нужно сделать, - это заставить метод run уловить любые изъяные из него исключения и обработать их в новом потоке.

Ответ 4

throws объявления являются частью подписи методов. Чтобы разрешить проверенные исключения для Runnable#run, нужно было объявить их в интерфейсе Runnable и приходилось try/catch при каждом запуске потока.

Затем мы обычно не называем метод run, мы его просто реализуем. Мы start() a Thread, а затем каким-то образом вызывается метод run.

Но самая очевидная причина: когда мы запускаем потоки, мы обычно не хотим ждать, пока метод run не закончит только такие исключения:

try {
   new Worker().start();  // now wait until run has finished
} catch (SomeThreadException oops) {
   // handle checked exception
}

Ответ 5

Причина в том, что исключение возвращается к вызывающему. Вызов метода run() не является вашим кодом. Это сам Хрэд. Так что даже если run() выдает исключение, программа не может его поймать.

Вы должны поместить результат выполнения потока в некоторую переменную уровня класса, а затем прочитать его оттуда. Или, альтернативно, используйте новый API: исполнители и интерфейс Callable, объявляющий метод call(), который возвращает будущий результат выполнения потока.

Ответ 6

Более очевидное решение для предыдущих ответов состоит в том, что если вы выбрали исключенное исключение, вы неправильно реализуете run(), как указано в интерфейсе runnable.

Он даже не компилируется:

run() in TestClass cannot implement run() in java.lang.Runnable; 
overridden method does not throw java.lang.Exception