自定义线程池如何捕获线程异常

最近写了个自定义的线程池,用于处理持续时间短、频次高的任务,逻辑上借鉴了CachedThreadPool,使用SynchronousQueue 作为任务的缓存队列,即实现没有任务进入队里,只要有空闲线程就执行任务。此外还自定义了拒接执行策略,由默认的异常拒绝执行,改为CallerRunsPolicy策略,并加了一行日志用作监控告警。
自定义线程池不是重点,本文的重点在线程池捕获异常的问题。

在实现该线程池的时候,笔者为其设置了一个ThreadFacotry,其中实现了UncaughtExceptionHandler,但是测试该线程池的时候,笔者发现,有些情况线程执行异常了,但是没有触发UncaughtExceptionHandler内部的逻辑(内部逻辑其实只是打日志监控)。

这就比较奇怪,后来对此作了查询,这里直接上结论和相关知识点,后面补一下来源:

如何捕获自定义线程池内的异常

对于线程池的execute(Runnable runnable)函数而言

:设置UncaughtExceptionHandler 是有用的,也应当设定,这样可以处理记录线程内未捕获的异常。

对于submit(Callable<T> callable)函数而言

设置UncaughtExceptionHandler 是没有用的,因为 该函数返回一个Future<T>的对象,如果线程执行过程中有未捕获异常,会被包在Future<T>对象中,不会抛出异常。对返回的Future调用get方法的时候,在get方法重新抛出包装之后的ExecutionException。这个异常内部包含线程执行过程抛出的异常。这里的思路是 线程执行的异常,也是返回值的一部分,由获取返回值的时候再次抛出。

逻辑上这样放着,对submit方法不做特殊操作是可以的,但是如果有强迫症一点,想给线程池的submit方法设置底层的处理异常的方法呢,也有办法,是ThreadPoolExecutor#afterExecute。如果执行之后有异常的话,该方法入参的Throwable参数不为null,可以在这里处理。

特例 SechduledThreadPool

SechduledThreadPool是个异类,该线程池的executesubmit方法都委托给了sechdule方法执行,会返回一个Future,这就意味着,SechduledThreadPool#execute 提交的任务,如果执行线程异常了,UncaughtExceptionHandler是捕获不到异常的,只能通过重写ThreadPoolExecutor#afterExecute实现。

参考来源

  1. http://literatejava.com/threading/silent-thread-death-unhandled-exceptions/
  2. https://stackoverflow.com/questions/1838923/why-is-uncaughtexceptionhandler-not-called-by-executorservice
  3. https://my.oschina.net/lifany/blog/884002
展开阅读全文
©️2020 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值