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 ...
随机推荐
- YbSoftwareFactory 代码生成插件【十六】:Web 下灵活、强大的审批流程实现(含流程控制组件、流程设计器和表单设计器)
程序=数据结构+算法,而企业级的软件=数据+流程,流程往往千差万别,客户自身有时都搞不清楚,随时变化的情况更是家常便饭,抛开功能等不谈,需求变化很大程度上就是流程的变化,流程的变化会给开发工作造成很大 ...
- dr.wondr博士随笔之某古旧非智能机T6XXX 恢复一例
大家好!欢迎再次来到dr.Wonde的微博! 今次我给大家带来索尼爱立信古董机T650i的取证工作展示! 首先请出今天我们的主角索尼爱立信 T650i>> 然后在工厂模式下,连接设备,看图 ...
- HashMap与ConcurrentHashMap的区别
从JDK1.2起,就有了HashMap,正如前一篇文章所说,HashMap不是线程安全的,因此多线程操作时需要格外小心. 在JDK1.5中,伟大的Doug Lea给我们带来了concurrent包,从 ...
- Java的文件读写操作
file(内存)----输入流---->[程序]----输出流---->file(内存) 当我们读写文本文件的时候,采用Reader是非常方便的,比如FileReader,InputStr ...
- Windows下的Objective-C集成开发环境(IDE)(转)
Objective-C是苹果软件的编程语言,想要上机学习.调试,有一个集成开发环境(IDE)方便很多.有三类方法搭建Objective-C的集成开发环境: 1) 使用苹果的平台,集成开发环境使用X ...
- jquery+javaScript完成瀑布流图片页面效果
效果如图: html: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> & ...
- 实时发布到tomcat
当我们在运用eclipse进行web项目的文件编写的时候,希望编写的东西可以实时的发布在tomcat的webapps文件夹之中,那么我们应该怎么做呢!下面就是操作方法: 1. 首先你的eclips ...
- response项目的各个写法
这个是一个响应式的页面 原文可参照:http://localhost/response/seejs_index.html
- Android first---xml文件生成与解析
一.使用append进行xml生成 Message类属性:private String body; private String date; private String a ...
- Android Gallery
xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android= ...