线程异常捕获

由于Java线程的本质特征,当抛出异常的时候就终止了如果再进行catch,都不在一个线程里面,所以无法捕捉到异常。

Java线程中,要在run()方法中把一切的异常都处理掉,可以使用try-catch块。不能让这个线程抛出异常,因为如果我们不使用特殊的方式的话,我们是无法捕获从这个线程中逃逸的异常的。异常一旦抛出了,那么这个线程就会停止运行,但是不会影响主线程和其它的线程。因为主线程和其它的线程都不知道它抛出了异常。

先给出一个例子,线程在run()方法中抛出异常,看main函数能不能catch到。

ExceptionThread.java

package thread.uncaughtException;

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

/**
 * Created by louyuting on 2017/3/11.
 */
public class ExceptionThread implements Runnable{

    @Override
    public void run() {
        System.out.println("准备抛出异常");
        throw new RuntimeException();
    }

    public static void main(String[] args) {
        Thread thread = new Thread(new ExceptionThread());
            ExecutorService service = Executors.newCachedThreadPool();
            service.execute(thread);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

看看运行结果:

Exception in thread "pool-1-thread-1" java.lang.RuntimeException
    at thread.uncaughtException.ExceptionThread.run(ExceptionThread.java:14)
    at java.lang.Thread.run(Thread.java:745)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
准备抛出异常
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

明显就是没有catch到异常。 难道是因为我们没有再main函数里面用try catch块包围起来?接下来再做测试:

package thread.uncaughtException;

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

/**
 * Created by louyuting on 2017/3/11.
 */
public class ExceptionThread implements Runnable{

    @Override
    public void run() {
        System.out.println("准备抛出异常");
        throw new RuntimeException();
    }

    public static void main(String[] args) {
        Thread thread = new Thread(new ExceptionThread());

        try {
            ExecutorService service = Executors.newCachedThreadPool();
            service.execute(thread);
        } catch (Exception e) {
            System.out.println("我捕捉到异常了");
            e.printStackTrace();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

运行结果:

Exception in thread "pool-1-thread-1" java.lang.RuntimeException
    at thread.uncaughtException.ExceptionThread.run(ExceptionThread.java:14)
    at java.lang.Thread.run(Thread.java:745)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
准备抛出异常
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

运行结果还是一样,说明并不是因为这个原因。

想想一个线程的抛出异常之后就终止了如果再进行catch,都不在一个线程里面。

为了解决这个问题,这个时候我们得去实现UncaughtExceptionHandler这个接口来捕获抛出的异常。UncaughtExceptionHandler是JDK5中的新接口,允许我们在每个线程上面都附加一个异常处理器,Thread.UncaughtExceptionHandler.uncaughtException()方法会在线程因未捕捉的异常而在临近死亡时被调用。为了使用这个异常处理器我们创建一个新的线程工厂ThreadFactory。并在new线程时设置UncaughtExceptionHandler。

HandlerThreadFactory.java

package thread.uncaughtException;

import java.util.concurrent.ThreadFactory;

/**
 * Created by louyuting on 2017/3/11.
 */
public class HandlerThreadFactory implements ThreadFactory {

    @Override
    public Thread newThread(Runnable r) {
        System.out.println(this + "creating new thread");
        Thread t = new Thread(r);
        System.out.println("created" + t);
        //为每一个线程设置异常捕获器
        t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
        System.out.println("eh = " + t.getUncaughtExceptionHandler());
        return t;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

这里创建两个抛出异常的线程类

public class ExceptionThread2 implements Runnable {
    @Override
    public void run() {
        Thread t = Thread.currentThread();
        System.out.println("run by " + t.getName());
        System.out.println("Exception " + t.getUncaughtExceptionHandler());
        throw new RuntimeException();
    }
}

public class ExceptionThread3 implements Runnable {
    @Override
    public void run() {
        Thread t = Thread.currentThread();
        System.out.println("run by " + t.getName());
        System.out.println("Exception " + t.getUncaughtExceptionHandler());
        throw new NullPointerException();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

实现我自己的异常处理器MyUncaughtExceptionHandler.java

public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler{

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("\n [caugth:] " + e.toString());
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

测试主函数:

public class CaptureUncaughtException {
    public static void main(String[] args) {
        ExecutorService es = Executors.newCachedThreadPool(new HandlerThreadFactory());
        es.execute(new ExceptionThread2());
        es.execute(new ExceptionThread3());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

运行结果是:
这里写图片描述

可知此时捕捉到了异常。

如果你知道将要在代码中处处使用相同的异常处理器,那么更加简单的方式是在Thread类中设置一个静态域,并将这个处理器设置为默认的未捕获异常的处理器。

public class SettingDefaultHandler {
    public static void main(String[] args) {
        //设置静态异常处理器
        Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());

        ExecutorService es = Executors.newCachedThreadPool();
        es.execute(new ExceptionThread2());
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值