线程捕捉异常

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

在这里插入图片描述

线程池自定义处理异常

在线程池,我们可以批量的为所有线程设置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("捕捉到了");
        }
    }

在这里插入图片描述

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值