JAVA 线程中的异常捕获
在java多线程程序中,所有线程都不允许抛出未捕获的checked exception(比如sleep时的InterruptedException),也就是说各个线程需要自己把自己的checked exception处理掉。这一点是通过java.lang.Runnable.run()方法声明(因为此方法声明上没有throw exception部分)进行了约束。但是线程依然有可能抛出unchecked exception(如运行时异常),当此类异常跑抛出时,线程就会终结,而对于主线程和其他线程完全不受影响,且完全感知不到某个线程抛出的异常(也是说完全无法catch到这个异常)。JVM的这种设计源自于这样一种理念:“线程是独立执行的代码片断,线程的问题应该由线程自己来解决,而不要委托到外部。”基于这样的设计理念,在Java中,线程方法的异常(无论是checked还是unchecked exception),都应该在线程代码边界之内(run方法内)进行try catch并处理掉.换句话说,我们不能捕获从线程中逃逸的异常。
看下面的例子:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class ExceptionThread implements Runnable { @Override
public void run() {
throw new RuntimeException("这个线程就干了这么一件事,抛出一个运行时异常");
} public static void main(String[] args) {
try {
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new ExceptionThread());
System.out.println("该干嘛干嘛去");
} catch (RuntimeException e) {
System.out.println("能不能捕获到异常?");
} } }

运行结果:
该干嘛干嘛去
Exception in thread "pool-1-thread-1" java.lang.RuntimeException: 这个线程就干了这么一件事,抛出一个运行时异常
at ExceptionThread.run(ExceptionThread.java:8)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
从运行结果中,我们可以看到的是,这个异常在main线程中没有catch到,即
System.out.println("能不能捕获到异常?");
永远不会执行到。
问题来了,我们如果需要捕获其线程的unchecked异常时该怎么办?Java SE5之后,我们可以通过Executor来解决这个我问题。为了解决这个问题,我们需要修改Executor产生线程的方式。Thread.UncaughtExceptionHandler是java SE5中的新接口,它允许我们在每一个Thread对象上添加一个异常处理器。(UncaughtExceptionHandler)。Thread.UncaughtExceptionHandler.uncaughtException()方法会在线程因未捕获的异常而面临死亡时被调用。下面这个例子简单的演示了如何使用UncaughtExceptionHandler
public class ExceptionThread2 implements Runnable { @Override public void run() { Thread t = Thread.currentThread(); System.out.println("run() by" + t); System.out.println("eh=" + t.getUncaughtExceptionHandler()); throw new RuntimeException("抛出运行时异常"); }} |

import java.lang.Thread.UncaughtExceptionHandler; /**
* 用于捕获异常---捕获的是uncheckedException
*
* @author February30th
*
*/
public class MyUnchecckedExceptionhandler implements UncaughtExceptionHandler { @Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("捕获到异常:" + e);
} }


import java.util.concurrent.ThreadFactory;
public class HandlerThreadFactory implements ThreadFactory {
@Override
public Thread newThread(Runnable r) {
System.out.println("创建一个新的线程");
Thread t = new Thread(r);
t.setUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());
System.out.println("eh121 = " + t.getUncaughtExceptionHandler());
return t;
}
}


import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class ThreadExceptionTest { /**
* @param args
*/
public static void main(String[] args) {
//下面有3中方式来执行线程。
//第1种按照普通的方式。这是能捕获到异常
Thread t = new Thread(new ExceptionThread2());
t.setUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());
t.start();
//第2种按照现成池,直接按照thread方式,此时不能捕获到异常,为什么呢?因为在下面代码中创建了一个线程,且设置了异常处理器,
//但是呢,在我们线程池中会重设置新的Thread对象,而这个Thread对象没有设置任何异常处理器,换句话说,我们在线程池外对线程做的
//任何操作都是没有用的
ExecutorService exec1 = Executors.newCachedThreadPool();
Runnable runnable = new ExceptionThread2();
Thread t1 = new Thread(runnable);
t1.setUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());
exec1.execute(runnable); //第3种情况一样的,也是走的线程池,但是呢是通过ThreadFactory方式,在ThreadFactory中会对线程做一些控制,可以设置异常处理器
//此时是可以捕获异常的。
ExecutorService exec = Executors.newCachedThreadPool(new HandlerThreadFactory());
exec.execute(new ExceptionThread2()); } }

运行结果
创建一个新的线程
eh121 = MyUnchecckedExceptionhandler@1b8e059
run() byThread[Thread-0,5,main]
eh=MyUnchecckedExceptionhandler@1b8e059
捕获到异常:java.lang.RuntimeException: 抛出运行时异常
从上述的运行结果中可以看到,未捕获的异常是通过uncaughtException来捕获的。
按照上述的实例,我们可以按照具体的情况,逐个地设置处理器。但是如果我们知道将要在代码的所有地方都是用相同的异常处理器,那么更简单的方式是在Thread类中设置一个静态域,并将这个处理器设置为默认的未捕获异常处理器。看下面的例子:
Thread.setDefaultUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());
ExecutorService exec = Executors.newCachedThreadPool(new HandlerThreadFactory());
exec.execute(new ExceptionThread2());
这个默认的处理器只有在线程不存在非默认的异常处理器时才会调用。 在运行时,系统会检查线程是否有属于自己的异常处理器,如果发现没有,就去检查相应的线程组是否有专有的异常处理器,如果发现也没有,再调用默认的异常处理器。
摘自:http://www.cnblogs.com/chenfei0801/archive/2013/04/23/3039286.html
JAVA 线程中的异常捕获的更多相关文章
- java主线程捕获子线程中的异常
本文主要参考:<think in java> 好,下面上货. 正常情况下,如果不做特殊的处理,在主线程中是不能够捕获到子线程中的异常的. 例如下面的情况. package com.xuey ...
- Java thread中对异常的处理策略
转载:http://shmilyaw-hotmail-com.iteye.com/blog/1881302 前言 想讨论这个话题有一段时间了.记得几年前的时候去面试,有人就问过我一个类似的问题.就是j ...
- java线程中的sleep/wait/notify/yield/interrupt方法 整理
java线程中的sleep/wait/notify/yield/interrupt方法 sleep 该方法能够使当前线程休眠一段时间 休眠期间,不释放锁 休眠时间结束之后,进入可执行状态,加入到线程就 ...
- java线程中的sleep和wait区别
面试题:java线程中sleep和wait的区别以及其资 ...
- 在Java 线程中返回值的用法
http://icgemu.iteye.com/blog/467848 在Java 线程中返回值的用法 博客分类: Java Javathread 有时在执行线程中需要在线程中返回一个值:常规中我们 ...
- .Net主线程扑捉子线程中的异常
首先看一段C#代码:运行后发现主线程通过try{}catch{}是不能扑捉子线程中的抛出来的异常. 代码 ); } public void run() { ...
- Swoole 中协程的使用注意事项及协程中的异常捕获
协程使用注意事项 协程内部禁止使用全局变量,以免发生数据错乱: 协程使用 use 关键字引入外部变量到当前作用域禁止使用引用,以免发生数据错乱: 不能使用类静态变量 Class::$array / 全 ...
- java线程基础巩固---如何捕获线程运行期间的异常
对于友盟统计我想搞程序的应该无人不晓,其中对于里面用得最多的功能就是对线上的崩溃进行修复,而这些异常都是运行期的,如: 其实也就是可以对线程中出现了这种运行期异常是提供有一种捕获机制对其进行统一处理, ...
- 第33节:Java面向对象中的异常
Java中的异常和错误 Java中的异常机制,更好地提升程序的健壮性 throwable为顶级,Error和Exception Error:虚拟机错误,内存溢出,线程死锁 Exception:Runt ...
随机推荐
- WebBrowser内核指定
一.背景 这几天在维护公司的一个项目,嗯…到现在七八年没人动过了(也是老古董了),都说N年前的代码碰不得 处处是坑 不能挖坑还得一步一步的填坑,恰好今天就填了一坑 此处作为记录 供以后翻阅,对代码除了 ...
- SQL2008完全卸载详解(图解)
一. SQL2008卸载. 1.从控制面板卸载 1)点击计算机右下角“开始”,点击“控制面板”
- wampserver 2.5多站点配置
wampserver2.5版本与之前老版本配置有区别,假设wamp安装在d:/wamp下.第一步:修改D:/wamp/bin/apache/apache2.4.9/conf/httpd.conf 文件 ...
- markdown-js 添加表格,代码块 parse
简介 markdown-js 是将 markdown转换成 HTML 的 JavaScript 库,我再网站中使用它来预览 markdown ,但是发现它对 代码块 和 表格 是不转换的.这么鸡肋的地 ...
- python_函数
一.map 遍历序列,对序列中每个元素进行操作,最终获取新的序列 li = [11,22,33,44] new_list = map(lambda a: a + 100,li) print(new_l ...
- SOA和WCF&WebAPI
SOA http://www.cnblogs.com/leslies2/archive/2011/12/12/2272722.html WCF开发框架形成之旅--如何实现X509证书加密 WebAPI ...
- Java8闭包
闭包在很多语言中都存在,例如C++,C#.闭包允许我们创建函数指针,并把它们作为参数传递,Java编程语言提供了接口的概念,接口中可以定义抽象方法,接口定义了API,并希望用户或者供应商来实现这些方法 ...
- [课程设计]Scrum 3.3 多鱼点餐系统开发进度(下单详细信息页面设计)
Scrum 3.3 多鱼点餐系统开发进度(下单详细信息页面设计) 1.团队名称:重案组 2.团队目标:长期经营,积累客户充分准备,伺机而行 3.团队口号:矢志不渝,追求完美 4.团队选题:餐厅到店点 ...
- [转载] SQL获取所有数据库名、表名、储存过程以及参数列表
查询一个数据库中所有表字段属性的sql语句 1.获取所有用户名: SELECT name FROM Sysusers where status='2' and islogin='1' is ...
- javascript作用域链与原型链有联系吗?
一般来说,作用域链是针对变量的,js里面大的范围上来说,只有两种作用域,全局作用域和函数内部作用域,如果函数1里面又定义了函数2(一般都是匿名函数), 那么就有了这么一个作用域链全局作用域==> ...