关闭

JAVA UncaughtExceptionHandler 处理

标签: javaexception线程
386人阅读 评论(0) 收藏 举报
分类:

Thread的run方法是不抛出任何检查型异常(checked exception)的,但是它自身却可能因为一个异常而被终止,导致这个线程的终结。最麻烦的是,在线程中抛出的异常即使使用try…catch也无法截获,因此可能导致一些问题出现,比如异常的时候无法回收一些系统资源,或者没有关闭当前的连接等等。
(PS:Callalble是可抛出异常)

如果需要捕获系统的未捕获异常(如系统抛出了未知错误,这种异常没有捕获,这将导致系统莫名奇妙的关闭,使得用户体验差),可以通过Thread.setUncaughtExceptionHandler(UncaughtExceptionHandler)来处理这种异常。

例子:

public class ExceptionHandler implements UncaughtExceptionHandler{

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("handle run in thread:"+Thread.currentThread().getName());

        System.out.println("thread:"+t.getName()+" throwing exception");
        e.printStackTrace();    
    }

}

public class Test implements Runnable{
    public static void main(String args[]) throws InterruptedException, FileNotFoundException, IOException, ClassNotFoundException 
    {

        Thread t=new Thread(new Test());
        t.setUncaughtExceptionHandler(new ExceptionHandler());
        t.start();
    }

输出:

run func
exception thread running:Thread-0
handle run in thread:Thread-0
thread:Thread-0 throwing exception
java.lang.RuntimeException
    at Test.fun(Test.java:43)
    at Test.run(Test.java:37)
    at java.lang.Thread.run(Unknown Source)

另外,这个例子同时也说明了异常处理函数UncaughtExceptionHandle是运行在抛出异常的线程中的。

如果是使用了线程池,那应该如何处理呢?
我们知道线程池中我们只能提交Runable,Callable对象,而不是Thread对象,代码类似与:

        ExecutorService pool=Executors.newCachedThreadPool();
        for(int i=0;i<10;i++)
        {
            Test task=new Test();
            pool.execute(task);
        }

为了能够也能设置UncaughtExceptionHandler,我们能够通过线程池的ThreadFactory,使得线程池中的线程特殊化。
代码如下:

import java.lang.Thread.UncaughtExceptionHandler;

public class ExceptionHandler implements UncaughtExceptionHandler{

    public static ExceptionHandler instance=new ExceptionHandler();

    public static ExceptionHandler getInstance()
    {
        return instance;
    }

    @Override
    synchronized public void uncaughtException(Thread t, Throwable e) {

        System.out.println("handle run in thread:"+Thread.currentThread().getName());       
        System.out.println("thread:"+t.getName()+" throwing exception");
        StackTraceElement ele[]  =e.getStackTrace();
        for(StackTraceElement s:ele)
        {
            System.out.println("\t"+s.toString());
        }

    }

}

上面的handle方法同步是为了输出信息更好辨认,并无其他特殊需求。

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;


class SpecialThreadFactory implements ThreadFactory{

    @Override
    public Thread newThread(Runnable r) {
        Thread t=new Thread(r);
        t.setUncaughtExceptionHandler(ExceptionHandler.getInstance());
        return t;
    }

}


public class Test implements Runnable{
    public static void main(String args[]) throws InterruptedException, FileNotFoundException, IOException, ClassNotFoundException 
    {
        ExecutorService pool=Executors.newCachedThreadPool(new SpecialThreadFactory());
        for(int i=0;i<10;i++)
        {
            Test task=new Test();
            pool.execute(task);
        }

        pool.shutdown();
    }

    @Override
    public void run() {
        fun();  
    }
    public static void fun()
    {
        throw new RuntimeException();
    }

}

结果

handle run in thread:Thread-1
thread:Thread-1 throwing exception
    Test.fun(Test.java:50)
    Test.run(Test.java:45)
    java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    java.lang.Thread.run(Unknown Source)
handle run in thread:Thread-3
thread:Thread-3 throwing exception
    Test.fun(Test.java:50)
    Test.run(Test.java:45)
    java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    java.lang.Thread.run(Unknown Source)
handle run in thread:Thread-5
thread:Thread-5 throwing exception
    Test.fun(Test.java:50)
    Test.run(Test.java:45)
    java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    java.lang.Thread.run(Unknown Source)
handle run in thread:Thread-7
thread:Thread-7 throwing exception
    Test.fun(Test.java:50)
    Test.run(Test.java:45)
    java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    java.lang.Thread.run(Unknown Source)
handle run in thread:Thread-9
thread:Thread-9 throwing exception
    Test.fun(Test.java:50)
    Test.run(Test.java:45)
    java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    java.lang.Thread.run(Unknown Source)
handle run in thread:Thread-0
thread:Thread-0 throwing exception
    Test.fun(Test.java:50)
    Test.run(Test.java:45)
    java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    java.lang.Thread.run(Unknown Source)
handle run in thread:Thread-2
thread:Thread-2 throwing exception
    Test.fun(Test.java:50)
    Test.run(Test.java:45)
    java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    java.lang.Thread.run(Unknown Source)
handle run in thread:Thread-4
thread:Thread-4 throwing exception
    Test.fun(Test.java:50)
    Test.run(Test.java:45)
    java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    java.lang.Thread.run(Unknown Source)
handle run in thread:Thread-6
thread:Thread-6 throwing exception
    Test.fun(Test.java:50)
    Test.run(Test.java:45)
    java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    java.lang.Thread.run(Unknown Source)
handle run in thread:Thread-8
thread:Thread-8 throwing exception
    Test.fun(Test.java:50)
    Test.run(Test.java:45)
    java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    java.lang.Thread.run(Unknown Source)

总结
1.UncaughtExceptionHandler用来处理线程未捕获异常,在发生异常的线程中运行处理代。
2.线程池中的线程通过ThreadFactory来进行UncaughtExeceptionHandle的注册。

3.突然想到一个问题:如果抛出异常的线程遇到不可恢复的异常,则还能运行handle相关代码么?

1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:42894次
    • 积分:1118
    • 等级:
    • 排名:千里之外
    • 原创:57篇
    • 转载:28篇
    • 译文:7篇
    • 评论:6条
    最新评论