由于异常不能跨线程传递,这就导致不能在主线程中处理子线程的异常,就像下面这样
class ExceptionTask implements Runnable {
@Override
public void run() {
System.out.println("Exception Task ");
throw new RuntimeException("Thread Exception");
}
}
public class ExceptionHandleTest {
public static void main(String[] args) {
try {
Thread thread = new Thread(new ExceptionTask());
thread.start();
}catch (Exception ex) {
ex.printStackTrace();
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
以上代码中main函数的try..catch无法捕获thread中的异常。
那么就只能用try..catch来处理每个线程的异常吗?在java 5中,提供了两种机制来更优雅的处理线程异常。
全局线程异常处理器
程序员可以定义自己的ExceptinHandler并将其设置到jvm上,这样所有的线程异常都交由这个异常处理器处理。
class ExceptionTask implements Runnable {
@Override
public void run() {
System.out.println("Exception Task ");
throw new RuntimeException("Thread Exception");
}
}
class CustomizeExceptionHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("catch thread exception:" + e);
}
}
public class ExceptionHandleTest {
public static void main(String[] args) {
//全局异常
Thread.setDefaultUncaughtExceptionHandler(new CustomizeExceptionHandler());
thread.start();
Thread thread2 = new Thread(new ExceptionTask());
thread2.start();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
输出结果:
Exception Task
catch thread exception:java.lang.RuntimeException: Thread Exception
Exception Task
catch thread exception:java.lang.RuntimeException: Thread Exception
- 1
- 2
- 3
- 4
这样,所有的线程异常都会被CustomizeExceptionHandler处理。
线程私有异常处理器
如果每个线程异常的处理策略不同,那么,也可以将异常处理器的适用范围设置到一个具体的线程上。
class ExceptionTask implements Runnable {
@Override
public void run() {
System.out.println("Exception Task ");
throw new RuntimeException("Thread Exception");
}
}
class CustomizeExceptionHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("catch thread exception:" + e);
}
}
class CustomizeExceptionHandler2 implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("catch thread exception2:" + e);
}
}
public class ExceptionHandleTest {
public static void main(String[] args) {
Thread thread = new Thread(new ExceptionTask());
thread.setUncaughtExceptionHandler(new CustomizeExceptionHandler());
thread.start();
Thread thread2 = new Thread(new ExceptionTask());
thread2.setUncaughtExceptionHandler(new CustomizeExceptionHandler2());
thread2.start();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
输出结果为:
Exception Task
catch thread exception:java.lang.RuntimeException: Thread Exception
Exception Task
catch thread exception2:java.lang.RuntimeException: Thread Exception
- 1
- 2
- 3
- 4
这样,每个线程就可以适用自己的异常处理器来处理各自的异常。
在线程池中使用异常处理器
在jdk1.5以后,推荐的使用线程的方式是线程池,那么,在线程池环境下如何设置线程的异常处理器呢?
由于线程池中的线程都是有ThreadFactory
产生的,所以,我们可以实现自己的ThreadFactory,为其产生的每个Thread实例设置一个异常处理器。
另外,也可以像全局线程异常处理器那样设置,但局限性会比较大。
下面看一个如何通过自定义ThreadFactory
来设置异常处理器
//自定义ThreadFactory
class CustomizeThreadFactory implements ThreadFactory {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
//为产生的每个线程实例设置异常处理器
thread.setUncaughtExceptionHandler(new CustomizeExceptionHandler());
return thread;
}
}
class ExceptionTask implements Runnable {
@Override
public void run() {
System.out.println("Exception Task ");
throw new RuntimeException("Thread Exception");
}
}
//自定义异常处理器
class CustomizeExceptionHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("catch thread exception:" + e);
}
}
public class ExceptionHandleTest {
public static void main(String[] args) {
//为线程池指定线程工厂实例
ExecutorService executorService = Executors.newCachedThreadPool(new CustomizeThreadFactory());
executorService.execute(new ExceptionTask());
executorService.shutdown();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
输出结果为:
Exception Task
catch thread exception:java.lang.RuntimeException: Thread Exception
- 1
- 2
总结一下:
- 通过实现
Thread.UncaughtExceptionHandler
接口自定义线程异常处理器 - 通过
Thread.setDefaultUncaughtExceptionHandler()
设置全局异常处理器 - 通过
new Thread().setUncaughtExceptionHandler()
方法为每个线程实例设置异常处理器 - 通过实现
ThreadFactory
接口自定义线程工厂,来为线程池提供带有异常处理功能的线程实例。