1、异常不能跨线程传播
class ExceptionThread implements Runnable
{
@Override
public void run()
{
//这里只能抛运行时异常,Runnable.run不允许抛出未处理的非运行时异常
throw new RuntimeException("exception in new thread");
}
}
public class MultiThreadTest
{
public static void main(String[] args) throws InterruptedException
{
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new ExceptionThread());
exec.shutdown();
}
}
上述代码会在控制打印出异常
Exception in thread "pool-1-thread-1" java.lang.RuntimeException: exception in new thread
at grucee.multithread.ExceptionThread.run(MultiThreadTest.java:12)
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)
你可能会疑惑是否可以在main方法里面处理这个异常呢,下面我们来修改main方法,尝试catch这个异常
public static void main(String[] args) throws InterruptedException
{
try
{
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new ExceptionThread());
exec.shutdown();
} catch (RuntimeException e)
{
System.out.println("exception in main thread.");
}
}
很遗憾,上述代码所产生的输出和前面的实例一样。
总结:我们不可以跨线程捕获异常,即使main线程创建了抛出异常的新线程。
2、未捕获异常处理
Thread.UncaughtExceptionHandler是Java SE5中的新接口,它允许你在每个Thread对象上都附着一个异常处理器。Thread.UncaughtExceptionHandler.uncaughtException()会在线程因未捕获的异常而临近死亡时调用。
class MyExecutors
{
/**
* 设置线程池的属性,并且传入我们自己的线程工厂
*/
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
120L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}
}
/**
* 创建线程的工厂,设置线程的属性
*/
class MyThreadFactory implements ThreadFactory
{
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
return t;
}
}
/**
* 未捕获异常处理,在线程创建时设置
*/
class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler
{
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println(t.getName() + "," + e);
}
}
class TaskTest implements Runnable
{
@Override
public void run() {
throw new RuntimeException();
}
}
public class ThreadPoolTest
{
public static void main(String[] args)
{
ExecutorService exec = MyExecutors.newCachedThreadPool(new MyThreadFactory());
exec.execute(new TaskTest());
exec.shutdown();
}
}
此时,控制台会打印出Thread-0,java.lang.RuntimeException,这表示我们成功捕获了这个异常并进行了处理。
另外Thread.setDefaultUncaughtExceptionHandler可以设置默认的异常处理类,这个处理类只会在不存在线程专有的未捕获异常处理器的情况下才会被调用。