线程、调度线程池、异常

看dubbo源码的时候,发现下面一段代码。前段时间,因为也是类似的线程池,遇到一个坑,刚好这次又看到,所以准备好好研究下下面的粗体字设计的三个知识点:
线程、调度线程池、异常。
public class DubboMonitor implements Monitor {
private static final Logger logger = LoggerFactory.getLogger(DubboMonitor.class);
// 定时任务执行器
private final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3, new NamedThreadFactory("DubboMonitorSendTimer", true));

public DubboMonitor(Invoker<MonitorService> monitorInvoker, MonitorService monitorService) {
// 启动统计信息收集定时器
sendFuture = scheduledExecutorService.scheduleWithFixedDelay(new Runnable() {
public void run() {
// 收集统计信息
try {
send();
} catch (Throwable t) { // 防御性容错
logger.error("Unexpected error occur at send statistic, cause: " + t.getMessage(), t);
}
}
}, monitorInterval, monitorInterval, TimeUnit.MILLISECONDS);
}
...
线程与异常:1、异常是线程隔离的,简单讲就是如果某个线程中抛出了异常,其他线程是无法感知到的。我们对照dubbo的上面一段代码看下。
定时收集器的调度线程池(scheduledExecutorService)在启动各个子线程的时候,用了catch Throwable ,其实我们正常情况下,绝大部分时间都是直接catch到exception
这里为啥要到
Throwable呢? 其实这个还是很讲究的,
我们看下
scheduleWithFixedDelay的签名:
If any execution of the task encounters an exception, subsequent executions are suppressed.
如果任何一次执行遇到异常,后面的执行将会被压制即无法继续执行。
我之前使用的时候,只是捕获到exception,偶尔线上会出现任务不执行的情况,当时也不知道怎么回事,每次出现问题,并没有任何异常日志。因为
你在主线程无法捕获到线程池的子线程
里面的异常,所以当某个任务子线程抛出throwable时,主线程发现不了,这个异常信息也无法记录,所以很难定位,当时
只能通过重启项目解决。后来重构的时候,研究了线程池和异常的关系,
才找到具体的原因。
所以dubbo里面的直接捕获到Throwable,还是很讲究的。

总结,如果用调度线程池来做业务,一定要catch到
Throwable,以免出现小概率的问题,而无法定位。








原文地址:https://www.cnblogs.com/yipihema/p/6972826.html