Поток Java: метод Run не может генерировать проверенное исключение - PullRequest
18 голосов
/ 20 декабря 2010

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

Ответы [ 6 ]

19 голосов
/ 20 декабря 2010

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

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

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

 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?
9 голосов
/ 20 декабря 2010

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

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

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

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

1 голос
/ 20 декабря 2010

Предположим, что поток 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 генерирует исключение нулевого указателя.Должен ли он быть перехвачен блоком перехвата, связанным с потоком B, или блоком, связанным с обработкой новых заказов?

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

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

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

0 голосов
/ 20 декабря 2010

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

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

run() in TestClass cannot implement run() in java.lang.Runnable; 
overridden method does not throw java.lang.Exception  
0 голосов
/ 20 декабря 2010

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

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

0 голосов
/ 20 декабря 2010

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

Опять же, мы обычно не вызываем run метод, мы просто реализуем это.Мы start() поток, а затем, так или иначе, вызывается метод run.

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

try {
   new Worker().start();  // now wait until run has finished
} catch (SomeThreadException oops) {
   // handle checked exception
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...