1 子线程异常主线程无法感知
主线程可以轻松发现异常,子线程却不行
子线程异常无法用传统方法捕获
/**
* 单线程,抛出,处理,有异常堆栈 多线程,子线程发生异常,会有什么不同?
*/
public class ExceptionInChildThread {
public static void main(String[] args) {
new Thread(() -> {
throw new RuntimeException("子线程出错啦...");
}).start();
//依然还在执行
for (int i = 0; i < 6; i++) {
System.out.println(i);
}
}
}
/**
* 1. 不加try catch抛出4个异常,都带线程名字
* 2. 加了try catch,期望捕获到第一个线程的异常,线程234不应该运行,希望看到打印出Caught Exception
* 3. 执行时发现,根本没有Caught Exception,线程234依然运行并且抛出异常
*
* 说明线程的异常不能用传统方法捕获
*/
public class CantCatchDirectly implements Runnable {
@Override
public void run() {
throw new RuntimeException();
}
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("Caught Exception.");
}
}
}
2 如何处理异常
方案一(不推荐):手动在每个run方法里进行 try catch
public class CantCatchDirectly implements Runnable {
@Override
public void run() {
try {
throw new RuntimeException();
} catch (RuntimeException e) {
System.out.println("Caught Exception.");
}
}
public static void main(String[] args) throws InterruptedException {
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();
}
}
方案二(推荐):利用 UncaughtExceptionHandler
//java.lang.Thread.UncaughtExceptionHandler
@FunctionalInterface
public interface 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() + "异常");
}
}
/**
* 使用刚才自己写的UncaughtExceptionHandler
*/
public class UseOwnUncaughtExceptionHandler {
public static void main(String[] args) throws InterruptedException {
Runnable run = () -> {
throw new RuntimeException();
};
Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler("捕获器1"));
new Thread(run, "MyThread-1").start();
Thread.sleep(300);
new Thread(run, "MyThread-2").start();
Thread.sleep(300);
new Thread(run, "MyThread-3").start();
Thread.sleep(300);
new Thread(run, "MyThread-4").start();
}
}