1.为什么需要UncaughtExceptionHandler
- 主线程可以轻松发现异常,子线程却不行
public class ExceptionInChildThread implements Runnable {
public static void main(String[] args) {
new Thread(new ExceptionInChildThread()).start();
for (int i = 0; i < 1000; i++) {
System.out.println(i);
}
}
@Override
public void run() {
throw new RuntimeException();
}
}
0
1
...省略
827
828
Exception in thread "Thread-0" java.lang.RuntimeException
at com.kpioneer.thread.threadcoreknowledge.uncaughtexception.ExceptionInChildThread.run(ExceptionInChildThread.java:17)
at java.lang.Thread.run(Thread.java:748)
829
830
...省略
子线程抛出的异常淹没在其它日志中,难以发现
- 子线程异常无法用传统方法捕获
public class CantCatchDirectly implements Runnable {
public static void main(String[] args) throws InterruptedException {
try {
new Thread(new CantCatchDirectly(), "MyThread-1").start();
Thread.sleep(300);
new Thread(new CantCatchDirectly(), "MyThread-2").start();
Thread.sleep(300);
new Thread(new CantCatchDirectly(), "MyThread-3").start();
Thread.sleep(300);
new Thread(new CantCatchDirectly(), "MyThread-4").start();
} catch (RuntimeException e) {
System.out.println("main Caught Exception.");
}
}
@Override
public void run() {
throw new RuntimeException();
}
}
Exception in thread "MyThread-1" java.lang.RuntimeException
at com.kpioneer.thread.threadcoreknowledge.uncaughtexception.CantCatchDirectly.run(CantCatchDirectly.java:30)
at java.lang.Thread.run(Thread.java:748)
Exception in thread "MyThread-2" java.lang.RuntimeException
at com.kpioneer.thread.threadcoreknowledge.uncaughtexception.CantCatchDirectly.run(CantCatchDirectly.java:30)
at java.lang.Thread.run(Thread.java:748)
Exception in thread "MyThread-3" java.lang.RuntimeException
at com.kpioneer.thread.threadcoreknowledge.uncaughtexception.CantCatchDirectly.run(CantCatchDirectly.java:30)
at java.lang.Thread.run(Thread.java:748)
Exception in thread "MyThread-4" java.lang.RuntimeException
at com.kpioneer.thread.threadcoreknowledge.uncaughtexception.CantCatchDirectly.run(CantCatchDirectly.java:30)
at java.lang.Thread.run(Thread.java:748)
main Caught Exception. 并没有打印,同时线程停止。
- 不能直接捕获的后果
结果是子线程停止运行,打印堆栈信息,然而我们的业务逻辑没有去执行
2.两种解决办法
1. 手动在每个run方法里进行try catch(不推荐)
public class CantCatchDirectly implements Runnable {
public static void main(String[] args) throws InterruptedException {
try {
new Thread(new CantCatchDirectly(), "MyThread-1").start();
Thread.sleep(300);
new Thread(new CantCatchDirectly(), "MyThread-2").start();
Thread.sleep(300);
new Thread(new CantCatchDirectly(), "MyThread-3").start();
Thread.sleep(300);
new Thread(new CantCatchDirectly(), "MyThread-4").start();
} catch (RuntimeException e) {
System.out.println("main Caught Exception.");
}
}
@Override
public void run() {
try {
throw new RuntimeException();
} catch (RuntimeException e) {
System.out.println("Caught Exception.");
}
}
}
Caught Exception.
Caught Exception.
Caught Exception.
Caught Exception.
2. 利用UncaughtExceptionHandler(推荐)
方法
- UncaughtExceptionHandler接口
- void uncaughtException(Thread t, Throwable e);
/**
* 描述: 自己的MyUncaughtExceptionHanlder
*/
public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
private String name;
public MyUncaughtExceptionHandler(String name) {
this.name = name;
}
@Override
public void uncaughtException(Thread t, Throwable e) {
Logger logger = Logger.getAnonymousLogger();
logger.log(Level.WARNING, "线程异常,终止啦" + t.getName());
System.out.println(name + "捕获了异常" + t.getName() + "异常");
}
}
public class UseOwnUncaughtExceptionHandler implements Runnable {
public static void main(String[] args) throws InterruptedException {
Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler("捕获器1"));
new Thread(new UseOwnUncaughtExceptionHandler(), "MyThread-1").start();
Thread.sleep(300);
new Thread(new UseOwnUncaughtExceptionHandler(), "MyThread-2").start();
Thread.sleep(300);
new Thread(new UseOwnUncaughtExceptionHandler(), "MyThread-3").start();
Thread.sleep(300);
new Thread(new UseOwnUncaughtExceptionHandler(), "MyThread-4").start();
}
@Override
public void run() {
throw new RuntimeException();
}
}
十二月 24, 2020 10:49:44 上午 com.kpioneer.thread.threadcoreknowledge.uncaughtexception.MyUncaughtExceptionHandler uncaughtException
警告: 线程异常,终止啦MyThread-1
捕获器1捕获了异常MyThread-1异常
十二月 24, 2020 10:49:44 上午 com.kpioneer.thread.threadcoreknowledge.uncaughtexception.MyUncaughtExceptionHandler uncaughtException
警告: 线程异常,终止啦MyThread-2
捕获器1捕获了异常MyThread-2异常
十二月 24, 2020 10:49:44 上午 com.kpioneer.thread.threadcoreknowledge.uncaughtexception.MyUncaughtExceptionHandler uncaughtException
警告: 线程异常,终止啦MyThread-3
捕获器1捕获了异常MyThread-3异常
十二月 24, 2020 10:49:45 上午 com.kpioneer.thread.threadcoreknowledge.uncaughtexception.MyUncaughtExceptionHandler uncaughtException
警告: 线程异常,终止啦MyThread-4
捕获器1捕获了异常MyThread-4异常
网友评论