由于线程的本质特性,使得你不能捕获从线程中逃逸的异常。一旦异常逃出任务的run方法,就会向外传播到控制台,使得你除非采用特殊的步骤捕获这种异常。
下面的任务总是会抛出一个异常,该异常会传播到run方法的外部,并且main展示了当你运行它时所发生的事情:
/**
*
*/
package com.cxm.thread.exception;
/**
* @author admin
*
*/
public class ExceptionThread2 implements Runnable
{
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run()
{
throw new RuntimeException();
}
}
/**
*
*/
package com.cxm.thread.exception;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author admin
*
*/
public class CaptureUncaughException
{
/**
* @param args
*/
public static void main(String[] args)
{
ExecutorService exec = Executors.newCachedThreadPool();
// try{
exec.execute(new ExceptionThread2());
// }catch(RuntimeException e){
// System.out.println("caught "+ e);
// }finally{
// exec.shutdown();
// }
}
}
输出如下:
Exception in thread "pool-1-thread-1" java.lang.RuntimeException
at com.cxm.thread.exception.ExceptionThread2.run(ExceptionThread2.java:19)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
如果将main的主体放在try-catch中看下效果:
/**
*
*/
package com.cxm.thread.exception;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author admin
*
*/
public class CaptureUncaughException
{
/**
* @param args
*/
public static void main(String[] args)
{
ExecutorService exec = Executors.newCachedThreadPool();
try{
exec.execute(new ExceptionThread2());
}catch(RuntimeException e){
System.out.println("caught "+ e);
}finally{
exec.shutdown();
}
}
}
运行结果和上面的没有区别,也就说try-catch没有起到作用,那么怎样才能捕获到这一个异常呢?
为了解决这个问题,我们需要修改executor产生线程的方式。Thread.UncaughtExceptionHandler是java SE5中的一个新接口,它允许你在每个线程对象上负载一个异常处理器。Thread.UncaughtExceptionHandler.uncaughtException会在线程因未捕获到异常而濒临死亡时被调用,为了使用它,我们创建了一个新的ThreadFactory,将他创建的每一个线程上都附带一个异常处理器。
/**
*
*/
package com.cxm.thread.exception;
/**
* @author admin
*
*/
public class ExceptionThread2 implements Runnable
{
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run()
{
throw new RuntimeException();
}
}
/**
*
*/
package com.cxm.thread.exception;
/**
* @author admin
*
*/
public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler
{
@Override
public void uncaughtException(Thread thread, Throwable throwable)
{
// TODO Auto-generated method stub
System.out.println("caught "+throwable);
}
}
/**
*
*/
package com.cxm.thread.exception;
import java.util.concurrent.ThreadFactory;
/**
* @author admin
*
*/
public class HandlerThreadFactory implements ThreadFactory
{
/* (non-Javadoc)
* @see java.util.concurrent.ThreadFactory#newThread(java.lang.Runnable)
*/
@Override
public Thread newThread(Runnable runnable)
{
// TODO Auto-generated method stub
Thread t = new Thread(runnable);
t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
return t;
}
}
/**
*
*/
package com.cxm.thread.exception;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author admin
*
*/
public class CaptureUncaughException
{
/**
* @param args
*/
public static void main(String[] args)
{
ExecutorService exec = Executors.newCachedThreadPool(new HandlerThreadFactory());
try{
exec.execute(new ExceptionThread2());
}catch(RuntimeException e){
System.out.println("caught "+ e);
}finally{
exec.shutdown();
}
}
}
运行结果如下:
caught java.lang.RuntimeException
你可以看到未捕获的异常是通过uncaughtException来捕获的。