Java-线程池异常处理

线程池,在平时的项目开发中是很常见的,关于这方面的资料在网上应该也很多。

这次呢,主要是想总结一下,之前的项目中曾经遇到的一个坑。其实也是一个很简单的bug,就是线程池调度的线程抛异常了,但是没有捕捉,导致找到问题花费了不少时间。所以今天就想总结一下,有关线程池在调度线程的时候,线程抛异常的处理场景。

代码1:

public void demo1() {
        ExecutorService service = Executors.newFixedThreadPool(1);
        Thread thread = new Thread(() -> {
            throw new RuntimeException();
        });
        service.execute(thread);
    }

如果我们执行上面这段代码,在控制台上看到异常输出。可能多数同学会对此不会觉得问题,但是问题在于,但是在绝大数情况下很多线上的应用会关闭控制台的日志输出。所以在这种情况下,会导致线程的异常丢失情况。

所以正常的处理情况是,在逻辑代码里面增加捕获异常处理。

代码2:

public void demo2() {
        ExecutorService service = Executors.newFixedThreadPool(1);
        Thread thread = new Thread(() -> {
            try {
                throw new RuntimeException();
                } catch (Exception e) {
                    System.out.println("thread-demo2");
                    e.printStackTrace();
                }
        });
        service.execute(thread);
    }

这样子我们就可以在catch里面把异常信息输出到应用日志里面。

当然,也可以通过Thread类中提供的接口UncaughtExceptionHandler,我们就能为线程设置默认的异常处理机制

代码3:

public void demo3() {
        ExecutorService service = Executors.newFixedThreadPool(1);
        Thread thread = new Thread(() -> {
            throw new RuntimeException();
        });
        thread.setUncaughtExceptionHandler((t, e) -> {
            System.out.println("thread-demo3");
            e.printStackTrace();
        });
        service.execute(thread);
    }

 

上面讲得都是在线程的层面上设置异常处理的,那么如何为线程池ThreadPoolExecutor设置UncaughtExceptionHandler呢。

我们可以通过实现ThreadFactory这个接口,在调用Thread newThread(Runnable r)这个方法的时候,为新创建的线程设置

UncaughtExceptionHandler。当然,如果同学们觉得自己去写实现类麻烦的话,可以使用Apache Commons和Google Guava这两个Java类库提供的相应配置。

示例中使用了Guava提供的ThreadFactoryBuilder为例

代码4:

public void demo4() {
        ThreadFactory threadFactory = new ThreadFactoryBuilder()
                .setUncaughtExceptionHandler((t, e) -> {
                    System.out.println("thread-demo4");
                    e.printStackTrace();
                })
                .build();
        ExecutorService service = Executors.newSingleThreadExecutor(threadFactory);
        Thread thread = new Thread(() -> {
            throw new RuntimeException();
        });
        service.execute(thread);
    }

需要注意的是,对于submit(),UncaughtExceptionHandler不会生效,只能通过Future的get()方法获取线程的执行结果.

 

总结

上面就是线程和线程池对于异常处理的几种方式,try...catch与UncaughtExceptionHandler这两种方式相比的话,虽然说前者在代码上会出现重复,但是相对于后者UncaughtExceptionHandler来说,在线程池中使用的时候,都需要创建新的线程,再为其设置UncaughtExceptionHandler,效率层面会下降很多。所以,个人觉得try...catch虽然稍微繁琐,但是能够安全确保异常的捕获,自由度较高。

 

 

 

 

 

 

 

 

你可能感兴趣的:(java,java)