如何在Java中将异常传播到调用线程中
如何在Java中将异常传播到调用线程中
我有一个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("** 从主类抛出的运行时异常"); } System.out.println("主类停止"); } @Override public void run() { try { while(true) { System.out.println("** 开始"); sleep(2000); throw new RuntimeException("来自线程的异常"); } } catch (RuntimeException e) { System.out.println("** 从线程抛出的运行时异常"); throw e; } catch (InterruptedException e) {} } }
有人知道为什么吗?
这篇文章将讨论在Java中如何将异常传播到调用线程,首先我们来看一下异常在线程中的状态转换。下面的图示展示了线程在异常发生与否时的状态转换:
图片来源: http://www-public.imtbs-tsp.eu/~gibson/Teaching/CSC7322/L8-ExceptionsAndThreads.pdf
你创建了这个图吗?如果不是,那么它的来源是什么?
Java中如何将异常传播给调用线程?
Java中的异常是线程局部的,因此主线程实际上无法看到run
方法。建议您阅读更多关于线程工作原理的内容,但是简单总结一下:调用start
会启动一个与主线程完全无关的不同线程。调用join
只是等待该线程完成。在线程中抛出但从未捕获的异常会终止该线程,这就是为什么join
在主线程上返回,但异常本身会丢失的原因。
如果您想要知道这些未捕获异常,可以尝试以下方法:
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { public void uncaughtException(Thread t, Throwable e) { System.out.println("Caught " + e); } });
有关未捕获异常处理的更多信息可以在这里找到。
我喜欢这个方法!使用静态方法Thread.setDefaultUncaughtExceptionHandler()
设置处理程序也可以捕获主线程中的异常。
在Java中,如果想要将异常传播到调用线程,可以使用Thread.UncaughtExceptionHandler。以下是一个示例代码:
Thread.UncaughtExceptionHandler h = new Thread.UncaughtExceptionHandler() { public void uncaughtException(Thread th, Throwable ex) { System.out.println("Uncaught exception: " + ex); } }; Thread t = new Thread() { 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();
如果想要将异常传播到上一层级,可以将异常保存到一个volatile变量中,使得上一层级可以在异常处理器中看到。在外部,可以检查变量是否为null,如果不为null,则抛出异常。或者可以通过扩展UncaughtExceptionHandler,添加一个volatile字段,并将异常存储在其中。
有人询问如何在不停止线程的情况下捕获线程内部的异常。然而,由于异常无法跨线程边界抛出,因此无法将异常直接抛到上一层级。在这种情况下,最好的方法是让异常处理器将未捕获的异常对象放入一个队列中,并让主线程定期检查队列以确定是否有异常抛出。
,要将异常传播到调用线程,可以使用Thread.UncaughtExceptionHandler。要将异常传播到上一层级,可以使用volatile变量或扩展UncaughtExceptionHandler并将异常存储在其中。如果要在不停止线程的情况下捕获线程内部的异常,可以使用异常处理器将异常对象放入队列中,并由主线程定期检查队列。