原文网址:Java多线程--全局异常处理--方法/实例_IT利刃出鞘的博客-CSDN博客
简介说明
本文用示例介绍如何全局捕获处理Java多线程中的异常。
在Java中,线程中的异常是不能抛出到调用该线程的外部方法中捕获的,只能在线程内部进行捕获。
为什么不能抛出异常到外部线程捕获?
因为线程是独立执行的代码片断,线程的问题应该由线程自己来解决,而不要委托到外部。基于这样的设计理念,在Java中,线程方法的异常都应该在线程代码边界之内(run方法内)进行处理。换句话说,我们不能捕获从线程中逃逸的异常。
JDK如何控制线程异常不会跑到外部线程?
通过java.lang.Runnable.run()方法声明(因为此方法声明上没有throw exception部分)进行了约束。
如果在线程中抛出异常线程会怎么样?
线程会立即终结。
如何捕获线程中的异常?
法1:使用try-catch-finally来包含代码块
法2:使用全局异常处理 UncaughtExceptionHandler
UncaughtExceptionHandler能检测出某个线程由于未捕获的异常而终结的情况。当一个线程由于未捕获异常而退出时,JVM会把这个事件报告给应用程序提供的UncaughtExceptionHandler异常处理器(这是Thread类中的接口):
public interface UncaughtExceptionHanlder { void uncaughtException(Thread t, Throwable e); }
JDK5之后可以在每一个Thread对象上添加一个异常处理器UncaughtExceptionHandler 。Thread.UncaughtExceptionHandler.uncaughtException()方法会在线程因未捕获的异常而面临死亡时被调用。
实例:不捕获异常package com.example.a; class MyThread extends Thread { private String name; public MyThread(String name) { this.name = name; } @Override public void run() { System.out.println(name + ":运行开始"); int i = 1 / 0; System.out.println(name + ":运行结束"); } } public class Demo { public static void main(String[] args) { System.out.println("主线程开始"); Thread thread = new Thread(new MyThread("线程1")); thread.start(); System.out.println("主线程结束"); } }
执行结果
主线程开始 主线程结束 线程1:运行开始 Exception in thread "Thread-1" java.lang.ArithmeticException: / by zero at com.example.a.MyThread.run(Demo.java:13) at java.lang.Thread.run(Thread.java:748)全局异常处理
本处只展示全局异常处理的方案。在线程代码里边加try catch这种方法就不贴出了,很基础。
法1,2,3也同样适用于Runnable方式创建的线程,比如:Thread thread = new Thread(new MyRunnable("线程1"));
法1:handlerpackage com.example.a; class MyThread extends Thread { private String name; public MyThread(String name) { this.name = name; } @Override public void run() { System.out.println(name + ":运行开始"); int i = 1 / 0; System.out.println(name + ":运行结束"); } } class MyUncheckedExceptionHandler implements Thread.UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println("捕获到异常。异常栈信息为:"); e.printStackTrace(); } } public class Demo { public static void main(String[] args) { System.out.println("主线程开始"); Thread thread = new Thread(new MyThread("线程1")); thread.setUncaughtExceptionHandler(new MyUncheckedExceptionHandler()); thread.start(); System.out.println("主线程结束"); } }
执行结果
主线程开始 主线程结束 线程1:运行开始 捕获到异常。异常栈信息为: java.lang.ArithmeticException: / by zero at com.example.a.MyThread.run(Demo.java:13) at java.lang.Thread.run(Thread.java:748)法2:线程组
package com.example.a; public class Demo { public static void main(String[] args) { System.out.println("主线程开始"); ThreadGroup threadGroup = new ThreadGroup("MyGroup") { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println("捕获到异常。异常栈信息为:"); e.printStackTrace(); } }; Thread thread = new Thread(threadGroup, new Runnable() { @Override public void run() { System.out.println("子线程运行开始"); int i = 1 / 0; System.out.println("子线程运行结束"); } }); thread.start(); System.out.println("主线程结束"); } }
运行结果
主线程开始 主线程结束 子线程运行开始 捕获到异常。异常栈信息为: java.lang.ArithmeticException: / by zero at com.example.a.Demo.run(Demo.java:19) at java.lang.Thread.run(Thread.java:748)法3:默认的handler
如果只需要一个线程异常处理器处理线程的异常,那么我们可以设置一个默认的线程异常处理器,当线程出现异常时,
如果没有指定线程的异常处理器,而且线程组也没有设置,那么就会使用默认的线程异常处理器
package com.example.a; class MyThread extends Thread { private String name; public MyThread(String name) { this.name = name; } @Override public void run() { System.out.println(name + ":运行开始"); int i = 1 / 0; System.out.println(name + ":运行结束"); } } class MyUncheckedExceptionHandler implements Thread.UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println("捕获到异常。异常栈信息为:"); e.printStackTrace(); } } public class Demo { public static void main(String[] args) { System.out.println("主线程开始"); Thread.setDefaultUncaughtExceptionHandler(new MyUncheckedExceptionHandler()); Thread thread = new Thread(new MyThread("线程1")); thread.start(); System.out.println("主线程结束"); } }
执行结果
主线程开始 主线程结束 线程1:运行开始 捕获到异常。异常栈信息为: java.lang.ArithmeticException: / by zero at com.example.a.MyThread.run(Demo.java:13) at java.lang.Thread.run(Thread.java:748)法4:FutureTask
上面说的3种方法都是基于线程异常处理器实现的,本方法不需要线程异常处理器。
package com.example.a; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class Demo { public static void main(String[] args) { System.out.println("主线程开始"); //1.创建FeatureTask FutureTaskfutureTask = new FutureTask<>(new Callable () { @Override public Integer call() throws Exception { System.out.println("子线程运行开始"); return 1 / 0; } }); //2.创建Thread Thread thread = new Thread(futureTask); //3.启动线程 thread.start(); try { Integer result = futureTask.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { //4.处理捕获的线程异常 System.out.println("捕获到异常。异常栈信息为:"); e.printStackTrace(); } System.out.println("主线程结束"); } }
执行结果
主线程开始 子线程运行开始 捕获到异常。异常栈信息为: 主线程结束 java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero at java.util.concurrent.FutureTask.report(FutureTask.java:122) at java.util.concurrent.FutureTask.get(FutureTask.java:192) at com.example.a.Demo.main(Demo.java:27) Caused by: java.lang.ArithmeticException: / by zero at com.example.a.Demo.call(Demo.java:16) at com.example.a.Demo.call(Demo.java:12) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.lang.Thread.run(Thread.java:748)
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)