Java线程池拒绝策略解析

开发 后端
为什么会有拒绝策略?线程池工作中,当任务量很大,超过系统实际承载能力时,如果不去搭理它,系统很可能崩溃,所以jdk内置提供了四种线程池的拒绝策略,可以合理解决这种问题。当线程池中线程已用完不能再创建,等待队列也排满,如果此时再有新任务,就会触发执行拒绝策略之一。

 为什么会有拒绝策略?线程池工作中,当任务量很大,超过系统实际承载能力时,如果不去搭理它,系统很可能崩溃,所以jdk内置提供了四种线程池的拒绝策略,可以合理解决这种问题。当线程池中线程已用完不能再创建,等待队列也排满,如果此时再有新任务,就会触发执行拒绝策略之一。

 

Java线程池拒绝策略解析

 

一、CallerRunsPolicy(调用者运行策略)

一般在不允许失败的、对性能要求不高、并发量较小的场景下使用,因为线程池一般情况下不会关闭,也就是提交的任务一定会被运行,但是由于是调用者线程自己执行的,当多次提交任务时,就会阻塞后续任务执行,性能和效率自然就慢了。当触发拒绝策略时,只要线程池没有关闭,就由提交任务的当前线程处理。

二、AbortPolicy(中止策略)

当触发拒绝策略时,它就会直接抛出拒绝执行的异常,中止策略就是直接打断当前执行的流程。它没有特殊的使用场景,但是一点要正确处理抛出的异常。ThreadPoolExecutor中默认的策略就是AbortPolicy,ExecutorService接口的系列ThreadPoolExecutor因为都没有显示的设置拒绝策略,所以默认的都是这个。但是请注意,ExecutorService中的线程池实例队列都是无界的,也就是说把内存撑爆了都不会触发拒绝策略。当自己自定义线程池实例时,使用这个策略一定要处理好触发策略时抛的异常,因为他会打断当前的执行流程。

三、DiscardPolicy(丢弃策略)

如果你提交的任务无关紧要,你就可以使用它 。因为它就是个空实现,会悄无声息的吞噬你的的任务。它就是直接静悄悄的丢弃这个任务,不触发任何动作。所以这个策略基本上不用了。

四、DiscardOldestPolicy(弃老策略)

这个策略依然会丢弃任务,丢弃时也是无声无息,但丢弃的是老的未执行的任务,而且是待执行优先级较高的任务。基于这个特性,我能想到的场景就是,发布消息,和修改消息,当消息发布出去后,还未执行,此时更新的消息又来了,这时未执行的消息的版本比现在低就可以被丢弃了。因为队列中还可能存在消息版本更低的消息会排队执行,所以在真正处理消息的时候一定要做好消息的版本比较。此拒绝策略,是一种喜新厌旧的拒绝策略。是否要采用此种拒绝策略,还得根据实际业务是否允许丢弃老任务来认真衡量。

第三方实现的拒绝策略

dubbo中的线程拒绝策略

可以看到,当dubbo的工作线程触发了线程拒绝后,主要做了三个事情,原则就是尽量让使用者清楚触发线程拒绝策略的真实原因。

输出了一条警告级别的日志,日志内容为线程池的详细设置参数,以及线程池当前的状态,还有当前拒绝任务的一些详细信息。可以说,这条日志,使用dubbo的有过生产运维经验的或多或少是见过的,这个日志简直就是日志打印的典范,其他的日志打印的典范还有spring。得益于这么详细的日志,可以很容易定位到问题所在。

Netty中的线程池拒绝策略

Netty中的实现很像JDK中的CallerRunsPolicy。不同的是,调用者运行策略是直接在调用者线程执行的任务。而 Netty是新建了一个线程来处理的。所以,Netty的使用面就可以扩展到支持高效率高性能的场景。但也要注意,Netty的实现里,在创建线程时未做任何的判断约束。

pinpoint中的线程池拒绝策略

pinpoint的拒绝策略实现很有特色,与众不同。他定义了一个拒绝策略链,包装了一个拒绝策略列表,当触发拒绝策略时,会将策略链中的rejectedExecution依次执行一遍

最后希望读完本文能让你对java线程池拒绝策略有更加细致的了解,可以根据不同的使用场景灵活运用。

责任编辑:华轩 来源: 今日头条
相关推荐

2020-07-08 12:05:55

Java线程池策略

2020-02-18 14:25:51

Java线程池拒绝策略

2022-03-14 07:32:06

线程池拒绝策略自定义

2023-08-15 15:33:29

线程池线程数

2011-06-22 15:50:45

QT 线程

2023-12-29 09:38:00

Java线程池

2024-01-08 09:09:40

线程池异常黑洞Futrue

2011-08-19 17:36:42

iPhone操作队列Java

2013-06-08 10:11:31

Java线程池架构

2015-10-10 09:39:42

Java线程池源码解析

2022-12-16 08:31:37

调度线程池源码

2021-05-26 11:30:24

Java线程池代码

2012-05-15 02:18:31

Java线程池

2020-02-11 17:15:09

开发者抛弃 Executors

2012-02-29 13:26:20

Java

2020-09-04 10:29:47

Java线程池并发

2020-12-08 08:53:53

编程ThreadPoolE线程池

2015-08-20 09:17:36

Java线程池

2012-02-01 11:20:23

Java线程

2023-11-22 08:37:40

Java线程池
点赞
收藏

51CTO技术栈公众号