由于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);
    }
}

看看运行结果:

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)
准备抛出异常

明显就是没有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();
        }
    }
}

运行结果:

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)
准备抛出异常

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

想想一个线程的抛出异常之后就终止了如果再进行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;
    }
}

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

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();
    }
}

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

public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler{

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

}

测试主函数:

public class CaptureUncaughtException {
    public static void main(String[] args) {
        ExecutorService es = Executors.newCachedThreadPool(new HandlerThreadFactory());
        es.execute(new ExceptionThread2());
        es.execute(new ExceptionThread3());
    }
}

运行结果是:

java 线程莫名被挂起 java线程异常会退出吗_抛出异常

可知此时捕捉到了异常。

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

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

        ExecutorService es = Executors.newCachedThreadPool();
        es.execute(new ExceptionThread2());
    }
}