关于java多线程中异常捕获的理解

在java多线程程序中,全部线程都不容许抛出未捕获的checked exception(好比sleep时的InterruptedException)也就是说各个线程须要本身把本身的checked exception处理掉java

这句话怎么理解,最简单的看下图,也就是不能在Runnable的run方法上抛出异常,必须在里面捕获多线程

这一点是经过java.lang.Runnable.run()方法声明(由于此方法声明上没有throw exception部分)进行了约束。可是线程依然有可能抛出unchecked exception(如运行时异常),当此类异常跑抛出时,线程就会终结,而对于主线程和其余线程彻底不受影响,且彻底感知不到某个线程抛出的异常(也是说彻底没法catch到这个异常)。JVM的这种设计源自于这样一种理念:“线程是独立执行的代码片段,线程的问题应该由线程本身来解决,而不要委托到外部。”基于这样的设计理念,在Java中,线程方法的异常(不管是checked仍是unchecked exception),都应该在线程代码边界以内(run方法内)进行try catch并处理掉.换句话说,咱们不能捕获从线程中逃逸的异常。ide

看下面的例子:spa

public class ExceptionTest {

    public static void main(String[] args) {
        
        try {
            new Thread(new ExceptionTask()).start();
        } catch (Exception e) {
            System.out.println("注意看我是否能打印。。。");
            e.printStackTrace();
        }
    }
    
}

class ExceptionTask implements Runnable {

    @Override
    public void run() {
        System.out.println("".substring(0, 10));
    }
    
}

打印结果线程

Exception in thread "Thread-0" java.lang.StringIndexOutOfBoundsException: String index out of range: 10
    at java.lang.String.substring(Unknown Source)
    at com.actuator.ExceptionTask.run(ExceptionTest.java:21)
    at java.lang.Thread.run(Unknown Source)

从运行结果中,咱们能够看到的是,"Thread-0"线程里的异常在main线程中没有catch到设计

问题来了,咱们若是须要捕获"Thread-0"线程的unchecked异常时该怎么办?Java SE5以后,咱们能够经过Executor来解决这个问题。code

Thread.UncaughtExceptionHandler是java SE5中的新接口,它容许咱们在每个Thread对象上添加一个异常处理器。(UncaughtExceptionHandler)。Thread.UncaughtExceptionHandler.uncaughtException()方法会在线程因未捕获的异常而面临死亡时被调用对象

下面这个例子简单的演示了如何使用UncaughtExceptionHandler。blog

import java.lang.Thread.UncaughtExceptionHandler;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

public class ExceptionTest {

    public static void main(String[] args) {
        
        // 下面有两种方式来执行线程
        
        // 第一种,非线程池写法
        Thread t = new Thread(new ExceptionTask());
        t.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                System.out.println("线程"+t.getName()+"捕获到异常:"+e.getMessage());
            }
        });
        t.start();
        
        // 第二种,线程池写法
        ExecutorService executorService = Executors.newCachedThreadPool(new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r);
                t.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
                    @Override
                    public void uncaughtException(Thread t, Throwable e) {
                        System.out.println("线程"+t.getName()+"捕获到异常:"+e.getMessage());
                    }
                });
                return t;
            }
        });
        executorService.execute(new ExceptionTask());
        
        
        
    }
    
}

class ExceptionTask implements Runnable {

    @Override
    public void run() {
        System.out.println("".substring(0, 10));
    }
    
}

两个执行结果同样接口

线程Thread-0捕获到异常:String index out of range: 10