中易网

为什么用线程的UncaughtExceptionHandler处理异常

答案:1  悬赏:60  
解决时间 2021-02-12 08:36
为什么用线程的UncaughtExceptionHandler处理异常
最佳答案
由于线程的本质特性,使得你不能捕获从线程中逃逸的异常。一旦异常逃出任务的run()方法它就会向外传播到控制台,除非你采取特殊的步骤捕获这种
错误的异常。在Java SE5之前,你可以使用线程组来捕捉这种异常,但是有了Java SE5,就可以用Executor来解决这个问题了。

下面的任务总是会抛出一个异常,该异常会传播到其run()方法的外部,并且main()展示了当你运行它时所发生的事情:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExceptionThread implements Runnable {
public void run() {
throw new RuntimeException();
}
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
service.execute(new ExceptionThread());
}
}

输出如下:
Exception in thread "pool-1-thread-1" java.lang.RuntimeException
at com.abc.thread.ExceptionThread.run(ExceptionThread.java:6)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)

将main的主体放在try-catch语句块中也是没有作用的:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExceptionThread implements Runnable {
public void run() {
throw new RuntimeException();
}
public static void main(String[] args) {
try {
ExecutorService service = Executors.newCachedThreadPool();
service.execute(new ExceptionThread());
} catch (RuntimeException e) {
System.out.println("Catched Runtime Exception.");
}
}
}

这将产生于前面示例相同的结果:未捕获的异常。

为了解决这个问题,我们要修改Executor产生线程的方式。Thread.UncaughtExceptionHandler是Java
SE5中的新接口,它允许你在每个Thread对象上都附着一个异常处理器。
Thread.UncaughtExceptionHandler.uncaughtException()会在线程因未捕获的异常而临近死亡时被调用。
为了使用它,我们创建了一个新类型的ThreadFactory,它将在每个新创建的Thread对象上附着一个
Thread.UncaughtExceptionHandler。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

public class ExceptionThread2 implements Runnable {
public void run() {
throw new RuntimeException("NullPointer");
}

public static void main(String[] args) {
ThreadFactory tFactory = new MyThreadFactory();
ExecutorService service = Executors.newCachedThreadPool(tFactory);
Runnable task = new ExceptionThread2();
service.execute(task);
}
}

class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
// 处理从线程里抛出来的异常。
public void uncaughtException(Thread t, Throwable e) {
System.out.println("Catched Throwable: " +
e.getClass().getSimpleName() + ", " + e.getMessage());
}
}

class MyThreadFactory implements ThreadFactory {
// 重新组织创建线程的方式
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
// 为每一个线程都绑定一个异常处理器。
t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
System.out.println("Thread[" + t.getName() + "] created.");
return t;
}
}

执行的结果如下:

可以看到,线程池中有2个线程,当一个线程发生异常时,该异常被捕捉了。

上面的示例使得你可以按照具体情况(在newThread()方法中使用if, case等语句)为每个线程逐个的设置处理器。如果你知道将要在代码中处处使用相同的异常处理器,那么更简单的方式是在Thread类中设置一个静态域,并将这个处理器设置为默认的处理器即可:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SettingDefaultHandler {
public static void main(String[] args) {
// 为线程设置默认的异常处理器。
Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new ExceptionThread2());
}
}

这个处理器只有在不存在线程专有的未捕获异常处理器的情况下才会被调用。系统会检查线程专有版本,如果没有发现,则检查线程组是否有专有的
uncaughtException()方法,如果也没有,才会调用defaultUncaughtExceptionHandler。
我要举报
如以上问答内容为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
大家都在看
可有人知道阜阳到宁波的班车,号码大友班车,
网上的为什么老款奥迪A6那么便宜?才十万多点
江北文化广场我想知道这个在什么地方
深圳通是什么卡?
朋友不吃饭,怎样劝她吃饭?
医生写处方用什么书法?为何看不懂
剑峰邮政代办所在哪里啊,我有事要去这个地方
大专毕业生考上全日制研究生没有学士学位,毕
男人对睡过的女人是什么感情
自考本科 金融专业 课程学习排序问题
鸿源广告体验店地址在什么地方,想过去办事
为什么我台机玩英雄联盟很慢,走的时候很慢、
嫦娥 唐 李商隐中首句写云母屏风烛影为什么用
杭州湾国际酒店-会议室在哪里啊,我有事要去
高中毕业,农村户口,想去当女兵,没有关系能
推荐资讯
y=arccos(2sinx)的定义域是什么?
erp试验中为什么我没有费用项目分类
一个月字和会字组成一个字是什么字呢
从甲地到乙地,其中百分之四十是上坡路,百分
A股有腾讯这样好股票吗
欧洲艺术的起源
想成为一个室内设计师学会自己做3D家具模型吗
天天向上中出场有首歌词有hibaby的歌
我的MAC地址改了,怎么能查原来是多少呢
ipd6和ipd Air有什么区别?
武汉优优印在线图文广告公司在哪里啊,我有事
想用马爹利的酒瓶来装米酒,怎么装进去?
手机登qq时,显示手机磁盘不足,清理后重新登
刺客的套装怎么选啊?