Thread 方式指定未受检查的异常
啥叫为受检查异常呢?
定义: 程序运行的时候抛出且没有被程序捕获的异常或者错误。
定义自定的线程未受检查的异常处理器
public class UEHlogger implements Thread.UncaughtExceptionHandler{
@Override
public void uncaughtException(Thread t, Throwable e) {
Logger logger = Logger.getAnonymousLogger();
logger.log(Level.SEVERE,"捕获未受检的异常,线程名称:"+t.getName());
logger.log(Level.SEVERE,"线程发生中断,线程名称:"+t.getName(),e);
}
}
测试 用线程池设置
setDefaultUncaughtExceptionHandler() // 设置全局的默认未捕获错误信息代码
setUncaughtExceptionHandler() //设置当前线程的未捕获错误信息代码
使用线程池的时候请使用execute 执行而不是submit,因为submit执行的时候会使得,异常将会被包装,无法先上抛出,除非使用返回Future的get()方法才会,将异常信息返回
同时UncaughtExceptionHandler也将会失败
public class TestMain {
public static void main(String[] args) throws ExecutionException, InterruptedException {
UEHlogger handler=new UEHlogger();
User user=null;
Thread thread=new Thread(new Runnable() {
Throwable throwable=null;
@Override
public void run() {
try{
//认为制作除0异常
int result=8/0;
}catch ( Throwable e){
//退出线程
System.out.println("捕获到受检查异常......"+e.getMessage());
}
//再次抛出未检查的异常,测试异常处理器
// user.setName("空指针异常");
//测试能否继续执行
System.out.println("我还能执行=========");
}
});
//指定线程抛出异常以后应该如果处理
thread.setUncaughtExceptionHandler(handler);
//启动线程执行
thread.start();
//线程池测试
ExecutorService executorService =new ThreadPoolExecutor(2, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
executorService.execute(new Runnable() {
@Override
public void run() {
Thread.setDefaultUncaughtExceptionHandler(handler);
try{
//认为制作除0异常
int result=8/0;
}catch ( Throwable e){
//退出线程
System.out.println("捕获到受检查异常......"+e.getMessage());
}
//再次抛出未检查的异常,测试异常处理器
user.setName("空指针异常");
//测试能否继续执行
System.out.println("我还能执行=========");
}
});
//
Integer result=null;
Callable<Integer> callable=()->{
System.out.println("=====进入callAble");
return 99/0;
};
Future<Integer> submit = executorService.submit(callable);
//使用submit的方式如果有异常时不会显示出来的
submit.get();
executorService.shutdown();
}
class User{
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
也可以通过ThreadFactoryBuilder 指定未受检查异常处理器
无论是Callable还是Runable 都是如此
public class submit {
public static void main(String[] args) {
//自定一线程未捕获一异常处理器
UEHlogger handler=new UEHlogger();
//线程池测试
ExecutorService executorService =new ThreadPoolExecutor(2, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
//
Integer result=null;
Callable<Integer> callable=()->{
Thread.setDefaultUncaughtExceptionHandler(handler);
System.out.println("=====进入callAble");
//设置及未捕获异常处理器
return 99/0;
};
Future<Integer> submit = executorService.submit(callable);
//使用submit的方式如果有异常时不会显示出来的
try {
submit.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}finally {
executorService.shutdown();
}
}
}
原因分析
为什么会这样呢?查看 FutureTask 源码可以发现,在执行任务出现异常之后,异常存到了一个 outcome 字段中,只有在调用 get 方法获取 FutureTask 结果的时候,才会以 ExecutionException 的形式重新抛出异常
public void run() {
...
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
...
}
protected void setException(Throwable t) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = t;
UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
finishCompletion();
}
}
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
private V report(int s) throws ExecutionException {
Object x = outcome;
if (s == NORMAL)
return (V)x;
if (s >= CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable)x);
}