由于线程的本质特性,使得你不能捕获从线程中逃逸的异常,如:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class App { public static void main(String[] args) throws InterruptedException { try { ExecutorService exec = Executors.newCachedThreadPool(); exec.execute(new Task()); exec.shutdown(); } catch (Exception e) { System.out.println("异常:"+e.getMessage()); } } } /** * 定义任务 * * @author Administrator */ class Task implements Runnable { @Override public void run() { throw new RuntimeException("运行时错误"); } }
输出:
Exception in thread "pool-1-thread-1" java.lang.RuntimeException: 运行时错误
at Task.run(App.java:27)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
可以看到一旦异常逃逸出run方法,将直接传播到顶层,且捕获不了。当然你可以在run方法里处理这些异常,但如果不想再run里处理呢?
为了解决这个问题,我们需要修改Executors产生线程的方式,Thread.setUncaughtExceptionHandler是Java5的新接口,它允许你在每个Thread对象上附着一个异常处理器。Thread.setUncaughtExceptionHandler.uncaughtException()会在线程因未捕获的异常而临近死亡时被调用。这里仍然需要用到线程工厂ThreadFactory:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; public class App { public static void main(String[] args) throws InterruptedException { ExecutorService exec = Executors.newCachedThreadPool(new MyThreadFactory()); exec.execute(new Task()); exec.shutdown(); } } /** * 定义任务 * * @author Administrator */ class Task implements Runnable { @Override public void run() { throw new RuntimeException("运行时错误"); } } /** * 线程工厂 * @author Administrator * */ class MyThreadFactory implements ThreadFactory{ @Override public Thread newThread(Runnable r) { Thread t=new Thread(r); t.setUncaughtExceptionHandler(new MysetUncaughtExceptionHandler()); return t; } } /** * 异常处理器 * @author Administrator * */ class MysetUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler{ @Override public void uncaughtException(Thread t, Throwable e) { System.out.println("异常:"+e.getMessage()); } }
输出:
异常:运行时错误
其实在实际应用中根据定制,ThreadFactory是经常用到的。