Вопрос-ответ

How to catch an Exception from a thread

Как перехватить исключение из потока

У меня есть основной класс Java, в классе я запускаю новый поток, в основном он ожидает, пока поток не умрет. В какой-то момент я выдаю исключение во время выполнения из потока, но я не могу перехватить исключение, выданное из потока в основном классе.

Вот код:

public class Test extends Thread
{
public static void main(String[] args) throws InterruptedException
{
Test t = new Test();

try
{
t.start();
t.join();
}
catch(RuntimeException e)
{
System.out.println("** RuntimeException from main");
}

System.out.println("Main stoped");
}

@Override
public void run()
{
try
{
while(true)
{
System.out.println("** Started");

sleep(2000);

throw new RuntimeException("exception from thread");
}
}
catch (RuntimeException e)
{
System.out.println("** RuntimeException from thread");

throw e;
}
catch (InterruptedException e)
{

}
}
}

Кто-нибудь знает почему?

Переведено автоматически
Ответ 1

Используйте Thread.UncaughtExceptionHandler.

Thread.UncaughtExceptionHandler h = new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread th, Throwable ex) {
System.out.println("Uncaught exception: " + ex);
}
};
Thread t = new Thread() {
@Override
public void run() {
System.out.println("Sleeping ...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("Interrupted.");
}
System.out.println("Throwing exception ...");
throw new RuntimeException();
}
};
t.setUncaughtExceptionHandler(h);
t.start();
Ответ 2

Это потому, что исключения являются локальными для потока, и ваш основной поток фактически не видит run метод. Я предлагаю вам прочитать больше о том, как работает потоковая обработка, но чтобы быстро подвести итог: ваш вызов start запускает другой поток, совершенно не связанный с вашим основным потоком. Вызов join просто ожидает, пока это будет выполнено. Исключение, которое генерируется в потоке и никогда не перехватывается, завершает его, вот почему join возвращается в ваш основной поток, но само исключение теряется.

Если вы хотите быть в курсе этих неперехваченных исключений, вы можете попробовать это:

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("Caught " + e);
}
});

Более подробную информацию об обработке неперехваченных исключений можно найти здесь.

Ответ 3

Это объясняет переход состояний потоков в зависимости от того, возникло исключение или нет:

Потоки и обработка исключений

Источник : http://www-public.imtbs-tsp.eu /~gibson/Teaching/CSC7322/L8-ExceptionsAndThreads.pdf

Ответ 4

Скорее всего;


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

  • если вы хотите обработать исключение, просто сделайте это в потоке, который его выдал.

  • в этом примере вашему основному потоку не нужно ждать от фонового потока, что на самом деле означает, что вам вообще не нужен фоновый поток.

Однако давайте предположим, что вам действительно нужно обработать исключение из другого дочернего потока. Я бы использовал ExecutorService, подобный этому:

ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Void> future = executor.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
System.out.println("** Started");
Thread.sleep(2000);
throw new IllegalStateException("exception from thread");
}
});
try {
future.get(); // raises ExecutionException for any uncaught exception in child
} catch (ExecutionException e) {
System.out.println("** RuntimeException from thread ");
e.getCause().printStackTrace(System.out);
}
executor.shutdown();
System.out.println("** Main stopped");

С принтами

** Started
** RuntimeException from thread
java.lang.IllegalStateException: exception from thread
at Main$1.call(Main.java:11)
at Main$1.call(Main.java:6)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
** Main stopped
java multithreading