在使用线程池的时候,可能会遇到两种情况,导致线程会需要被拒绝。
- 调用 shutdown 等方法关闭线程池后,即便此时可能线程池内部依然有没执行完的任务正在执行,但是由于线程池已经关闭,此时如果再向线程池内提交任务,就会遭到拒绝。
- 线程池没有能力继续处理新提交的任务,也就是工作已经非常饱和的时候。
线程池的拒绝Handler
其实在这里,我们其实可以想到线程池的初始配置中有一个配置handler,这个其实就是为了解决这种问题而出现的,在线程池中,除了我们自己可以定义一个拒绝Handler策略,线程池其实也内置了四种不同的拒绝策略供我们使用。
线程策略
AbortPolicy(异常策略)
在遇到拒绝任务时,会直接抛出一个类型为 RejectedExecutionException 的 RuntimeException,所以我会叫他为异常策略,因为他会抛出异常。这个异常你可以捕获起来,然后做你想做的事。
DiscardPolicy(丢弃策略)
这个策略就比较悲伤了,当线程满了之后,后面想进来的线程会被直接丢弃掉,丢弃掉的线程后面不会再执行,也不会有通知,更不会有记录,所以这个策略比较危险,他会让线程人间蒸发。这样大家都不知道他有没有发生过。如果发生在业务上,可能会造成业务数据的丢失。
DiscardOldestPolicy (牺牲策略)
这个就比较残忍,虽然不会丢弃掉想要挤进来的线程,但是他会把线程队列中存活时间久的线程给丢弃掉,让想挤进来的线程去替代他。有点像渣男。可以把它叫为渣男策略
CallerRunsPolicy(执行策略)
这个策略就比较负责了,当线程池满了之后,想要进来的线程不会被丢弃,他会直接让提交线程的线程去执行这个线程任务,也是不进入到线程池,你直接就地解决吧。更简单的理解为,当遇到了这个策略,相当于这个线程池新增了一个线程资源。
这样的方式有两点好处
- 新提交的任务不会被丢弃,也就不会造成业务上的损失。
- 新提交的任务会让提交者的线程去执行,这个时候提交者的线程就会被阻塞一段时间,这段时间其实会给线程池减少一定程度的压力,减缓了提交者的去提交线程的速度。