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