Java线程的异常处理

基本

线程对于异常的处理:

public class ExceptionInRunnableTest {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            int i = 3 / 0;
        });

        thread.start();
    }
}

运行上述代码:控制台输出如图。

当一个线程因为抛出异常,结束整个run方法时,结束整个thread生命周期时,JVM会在控制台打印异常信息。

当java的jar包跑在linux系统中时,就是会将异常信息输出到标准输出流里。

进阶

Thread有一个setUncaughtExceptionHandler方法,

可以改变线程结束抛出异常时JVM对应的动作。

public class ExceptionInRunnableTest {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            int i = 3 / 0;
        });
        thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                long id = Thread.currentThread().getId();
                System.out.println(id);
                System.out.println(e);
            }
        });
        thread.start();
    }
}

运行上述代码:控制台输出如图:

可以发现此时输出的就不再时JVM原本输出的异常栈信息,而是我们定制的信息。

如果此时我们的代码写的不好导致异常信息没有被正确的记录,那么整个异常信息就会直接被吞掉,无法知道发生了什么。只能知道这个线程”诡异”的结束了。

如果此时我们代码是使用日志框架记录了异常:log.error(xxxx,e); 那么异常信息就会进入我们的日志文件,而不是由JVM输出到标准输出。

线程池

事实上在真实的java应用中,我们几乎很少会单独起一个线程做什么事儿,都是启动一个线程池。

此时我们不会主动new Thread,也就没地方去设置setUncaughtExceptionHandler方法。

那么想定制异常信息输出到日志文件,jdk的线程池提供了类似的方法:java.util.concurrent.ThreadPoolExecutor#afterExecute。作用和线程的setUncaughtExceptionHandler方法类似。也是用来定制处理线程结束时的逻辑。

但是这里有一个有趣的容易踩到的坑。如下的代码:

public class ExceptionPoolTest {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(1);
        Future<?> submit = executor.submit(new Runnable() {
            @Override
            public void run() {
                int i = 1 / 0;
            }
        });
    }
}

运行后,不会输出任何异常信息。

为啥呢?因为我们在提交任务时,使用的subimit方法,这个方法是会返回Future结果的。所以一个线程就算是异常结束了,产生的异常也会被封装在Future里,只有在调用Future.get方法时才会抛出。

而上面的代码根本就不需要返回结果。所以也就没用到future。所以异常就感觉是莫名其妙的不见了。所以使用线程池时要注意。如果不打算返回任何结果,直接使用execute方法即可,不要使用submit。否则在生产环境找不到异常日志就难受了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值