线程捕捉异常

在Java中,线程中的异常是不能抛出到调用该线程的外部方法中捕获的。

因为线程是独立执行的代码片断,线程的问题应该由线程自己来解决,而不要委托到外部。”基于这样的设计理念,在Java中,线程方法的异常都应该在线程代码边界之内(run方法内)进行try catch并处理掉,换句话说,我们不能捕获从线程中逃逸的异常。

    public static void main(String[] args){
     
        try {
     
            new Thread( () -> {
     
                int i =  1/ 0;
            }).start();
        }catch (Exception e){
     
            System.out.println(1);
        }
    }

在这里插入图片描述
可以看到,外部的catch并没有捕捉到。

Thread类的run()方法声明,方法声明上没有对抛出异常进行任何约束,也就是异常不会抛到外部。如果内部没有catch,那么Thread的默认异常处理就是调用 System.err 进行输出,也就是直接打印到控制台了。

解决方案

线程内部显式try…catch

    public static void main(String[] args){
     
        new Thread( () -> {
     
            try {
     
                int i =  1/ 0;
            }catch (Exception e){
     
                System.out.println("1");
            }
        }).start();
    }

在这里插入图片描述
可以看到我们在线程内部显式的进行try/catch,异常被捕获。

给线程定义异常处理器

查看Thread类的源码,我们可以看到有个dispatchUncaughtException方法,此方法就是用来处理线程中抛出的异常的。JVM会调用dispatchUncaughtException方法来寻找异常处理器(UncaughtExceptionHandler),处理异常。

    /**
     * Dispatch an uncaught exception to the handler. This method is
     * intended to be called only by the JVM.
     */
    private void dispatchUncaughtException(Throwable e) {
     
        getUncaughtExceptionHandler().uncaughtException(this, e);
    }
	/**
	 * 获取用来处理未捕获异常的handler,如果没有设置则返回当前线程所属的ThreadGroup
	 * 
	**/
    public UncaughtExceptionHandler getUncaughtExceptionHandler() {
     
        return uncaughtExceptionHandler != null ?
            uncaughtExceptionHandler : group;
    }

uncaughtExceptionHandler 默认为null,null的话就调用线程所属group的默认handler

	//  这里也就是打印到控制台
    public void uncaughtException(Thread t, Throwable e) {
     
        if (parent != null) {
     
            parent.uncaughtException(t, e);
        } else {
     
            Thread.UncaughtExceptionHandler ueh =
                Thread.getDefaultUncaughtExceptionHandler();
            if (ueh != null) {
     
                ueh.uncaughtException(t, e);
            } else if (!(e instanceof ThreadDeath)) {
     
                System.err.print("Exception in thread \""
                                 + t.getName() + "\" ");
                e.printStackTrace(System.err);
            }
        }
    }

所以我们可以通过设置Thread的uncaughtExceptionHandler 来设置异常处理器

    public static void main(String[] args){
     
        Thread thread = new Thread(() -> {
     
            int i = 1 / 0;
        });
        thread.setUncaughtExceptionHandler((t, e) -> System.out.println("捕捉到异常"));
        thread.start();
    }

线程捕捉异常_第1张图片

线程池自定义处理异常

在线程池,我们可以批量的为所有线程设置uncaughtExceptionHandler,线程是由ThreadFactory产生的,所以我们可以通过这里入手。

通过复写ThreadFactory的newThread就可实现。

public class ThreadExceptionDemo {
     

    private static final int CORE_POOL_SIZE = 3;
    private static final int MAX_POOL_SIZE = 100;
    private static final int QUEUE_CAPACITY = 5;
    private static final Long KEEP_ALIVE_TIME = 5L;

    public static void main(String[] args){
     
    	// 在构造函数塞进去我们要的ThreadFactory
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                CORE_POOL_SIZE,
                MAX_POOL_SIZE,
                KEEP_ALIVE_TIME,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(QUEUE_CAPACITY),
                new MyThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy());

        executor.execute(()->{
     
            int i = 1 / 0;
        });
    }
}
class MyThreadFactory implements ThreadFactory{
     

    @Override
    public Thread newThread(Runnable r) {
     
        Thread thread = new Thread(r);
        thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
     
            @Override
            public void uncaughtException(Thread t, Throwable e) {
     
                System.out.println("捕捉到了");
            }
        });

        return thread;
    }
}

在这里插入图片描述

通过Future的get方法捕获异常

线程池的submit是带有返回值的

    public static void main(String[] args){
     
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        Future future = executorService.submit(()->{
     
            int i = 1 / 0;
        });
        try {
     
            future.get();
        } catch (InterruptedException | ExecutionException e) {
     
            System.out.println("捕捉到了");
        }
    }

在这里插入图片描述

你可能感兴趣的:(java基础)