在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 线程中的异常捕获的更多相关文章

  1. java主线程捕获子线程中的异常

    本文主要参考:<think in java> 好,下面上货. 正常情况下,如果不做特殊的处理,在主线程中是不能够捕获到子线程中的异常的. 例如下面的情况. package com.xuey ...

  2. Java thread中对异常的处理策略

    转载:http://shmilyaw-hotmail-com.iteye.com/blog/1881302 前言 想讨论这个话题有一段时间了.记得几年前的时候去面试,有人就问过我一个类似的问题.就是j ...

  3. java线程中的sleep/wait/notify/yield/interrupt方法 整理

    java线程中的sleep/wait/notify/yield/interrupt方法 sleep 该方法能够使当前线程休眠一段时间 休眠期间,不释放锁 休眠时间结束之后,进入可执行状态,加入到线程就 ...

  4. java线程中的sleep和wait区别

                                                                            面试题:java线程中sleep和wait的区别以及其资 ...

  5. 在Java 线程中返回值的用法

    http://icgemu.iteye.com/blog/467848 在Java 线程中返回值的用法 博客分类: Java Javathread  有时在执行线程中需要在线程中返回一个值:常规中我们 ...

  6. .Net主线程扑捉子线程中的异常

    首先看一段C#代码:运行后发现主线程通过try{}catch{}是不能扑捉子线程中的抛出来的异常. 代码 );        }        public void run()        {   ...

  7. Swoole 中协程的使用注意事项及协程中的异常捕获

    协程使用注意事项 协程内部禁止使用全局变量,以免发生数据错乱: 协程使用 use 关键字引入外部变量到当前作用域禁止使用引用,以免发生数据错乱: 不能使用类静态变量 Class::$array / 全 ...

  8. java线程基础巩固---如何捕获线程运行期间的异常

    对于友盟统计我想搞程序的应该无人不晓,其中对于里面用得最多的功能就是对线上的崩溃进行修复,而这些异常都是运行期的,如: 其实也就是可以对线程中出现了这种运行期异常是提供有一种捕获机制对其进行统一处理, ...

  9. 第33节:Java面向对象中的异常

    Java中的异常和错误 Java中的异常机制,更好地提升程序的健壮性 throwable为顶级,Error和Exception Error:虚拟机错误,内存溢出,线程死锁 Exception:Runt ...

随机推荐

  1. html标签中meta属性使用介绍

    前言 meta是html语言head区的一个辅助性标签.也许你认为这些代码可有可无.其实如果你能够用好meta标签,会给你带来意想不到的效果,meta标签的作用有:搜索引擎优化(SEO),定义页面使用 ...

  2. 报表控件NCreport教程:子查询系统设计

    数据报表中经常需要用到主从数据关系,比如发票.订单等一类的特殊文件,在报表控件NCreport中也不例外.数据报表至少有一个表头和一个通过 主键和外键关联的相关细节数据集.子查询系统则是通过父数据源驱 ...

  3. Bash:-:-通过awk获取文本变量的赋值

    txt格式: ... logport='13000' sessionport='23000' ... ######################## 只获取logport的赋值13000 awk ' ...

  4. pt-online-schema-change原理解析

    都说pt-toolkit工具集中的pt-online-schema-change可以在线不锁表修改表结构,那么这个工具具体是什么原理呢,请见下面娓娓道来: 1.pt-online-schema-cha ...

  5. webstorm IDE添加Plugins----添加vue插件

    webstorm IDE很强大了,扩展性很强,语法校验很强大,不过有时候一些特殊的插件  还是需要自己添加到IDE的 下面以添加VUE Plugins 为例: Setting--Plugins[点下方 ...

  6. 。net 之view筛选

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...

  7. sdn

    #!/usr/bin/env python #from mininet.cli import CLI #from mininet.link import Link #from mininet.net ...

  8. [LeetCode_5] Longest Palindromic Substring

    LeetCode: 5. Longest Palindromic Substring class Solution { public: //动态规划算法 string longestPalindrom ...

  9. ZooKeeper测试笔记

    1. 下载ZooKeeper.官网:http://zookeeper.apache.org 下载后解压,假定zookeeper程序目录为/home/test/zookeeper,为陈述方便此目录记为 ...

  10. Shell脚本检测Tomcat是否正在运行

    #!/bin/sh # configurations # computer 设备名称 # target 监控目标 # watcher 跟踪者(邮箱) computer="ehetong&qu ...