如果在线程池中使用无界阻塞队列会发生什么问题?要回答这个问题首先要对线程池的工作原理非常熟悉,如果忘了的可以看下这篇文章线程池的核心参数及工作原理。
线程池用无界阻塞队列会有什么影响
有一个面试题:在远程服务异常的情况下,使用无界阻塞队列是否会导致内存异常飙升?这个问题的意思是远程服务不可用会导致接口调用超时,新任务不断提交到线程池,队列变成得越来越大,此时会导致内存飙升起来,而且还可能会导致内存溢出OOM。通常线程池都是设置成有界队列加一个拒绝策略。
线程池内线程调用远程服务超时
有界队列可以避免内存溢出,但是如果线程池的核心参数maximumPoolSize=Integer.MAX_VALUE的话,代表你可以无限制的不停地创建额外的线程出来处理任务,一台机子有几千甚至几万个线程,我们知道每个线程都有自己的线程栈,是需要占用一定内存资源的,垃圾回收又回收不了,会导致内存资源被耗尽,系统也会崩溃掉,即使没有崩溃也会让机子的cpu负载特别高。所以线程池一般建议maximumPoolSize和corePoolSize设置成一样,当工作队列存满了之后,交给拒绝策略去处理。
线程池自带的四种拒绝策略
1、ThreadPoolExecutor.AbortPolicy
直接丢弃任务并抛出RejectedExecutionException异常,这是线程池默认的拒绝策略
2、ThreadPoolExecutor.DiscardPolicy
也是直接丢弃任务,但是不抛出异常
3、ThreadPoolExecutor.DiscardOldestPolicy
丢弃队列老的任务,然后重新尝试执行任务(重复此过程)
4、ThreadPoolExecutor.CallerRunsPolicy
由调用线程(理解成主线程)处理该任务
线程池队列满了,你该怎么办
真正的生产环境可以根据自己业务需要,选择通过实现RejectedExecutionHandler接口来自定义拒绝策略。比如把线程池无法执行的任务信息持久化写入数据库去,后台专门启动一个线程,后续等待线程池的工作负载降低了,这个后台线程就可以慢慢的从磁盘里读取之前持久化的任务重新提交到线程池。
线上机器宕机,线程池阻塞队列中的请求怎么办
我们知道队列里任务请求如果只在内存,没有持久化的话,机器宕机队列中的请求肯定会丢失。那么是不是可以在任务提交到线程池前,先把任务信息插入到数据库加个状态字段:未提交,当任务提交到线程池后,再更新状态为已提交,任务执行完之后再更新状态为已完成。机器宕机系统重启后,启动一个后台线程去读取未提交和已提交的任务信息,重新提交到线程池,继续执行任务。
原文地址:百度安全验证