https://open8gu.com/concurrent/thread-pool/cbrhx6xrc802t8sy/
如果项目运行过程中,线程池中有大量的线程正在运行任务或者阻塞队列中存在大量的任务堆积,此时项目遇到重启或者宕机的情况,线程池会丢失运行中以及未运行的任务,导致业务异常。
针对这种场景,有两种解决方案,如下所示:
通过该方式可以极大程度避免应用关闭时线程池任务没有执行完成情况。当然,等待时间需要根据实际情况设置,如果说等待时间太久,会影响项目的重新发布效率。
不过如果线程池任务太多的话,还是有可能会出现到时间了任务还没跑完,最后依然丢任务的情况。
上面这种方式适合快速响应用户请求的类型,如果是快速处理批量任务则不适用,因为后者阻塞队列的数量可能会很多,基本上不可能等待所有任务完成。为此,要想做到数据不丢失场景,需要借助消息队列进行兜底消费。
如果发送任务,我们不是直接投递到线程池运行,而是投递到消息队列,比如 RocketMQ 等,然后在消息队列消费者逻辑中通过线程池进行消费。这样的话,即可以通过消息队列机制保障消息任务不丢失,同时通过线程池进行消费提速。
有种极端场景,不适合在回答问题时直接说,而是在面试官提出疑问后引出来。
我们将消息投递到线程池后,就返回给消息队列 ACK,此时应用突然宕机,任务在线程池中正在执行,结果还是会丢失。如果想要完全保证消息不丢失,应该在消息队列投递线程池前将任务备份到数据库,并在线程池中将任务设置完成状态。同时,有个异步任务定时扫描未完成的数据,完成最终一致性。
在消费者中的线程池尽量不要设置阻塞队列长度,同时,要加上优雅关闭线程池逻辑,这样能够最大可能性避免任务丢失场景。