NO.32 不堪重负:线程池拒绝策略

时间:2022-04-21
本文章向大家介绍NO.32 不堪重负:线程池拒绝策略,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

加入读书践行群,最【好学】的程序员都在这里!

碎片时间体系学习

这是程序员Chatbook第86篇原创

距离2018年还有1

今日难度系数 :

预计阅读时间 :3分钟

00、缘起缘灭

在前面几篇文章中,我们陆续聊到了线程池的底层核心实现ThreadPoolExecutor的方方面面,今天我们一起来看看其构造函数中的最后一个参数——拒绝策略。

当新到的任务数量已经超过了系统实际能够承载的能力时,就会触发执行拒绝策略,这是系统超负荷运行时的补救措施;具体表现在以下三个方面:

线程池中的线程已经用完了,无法再继续为新任务服务

等待队列已经排满了,再也不能容纳新的任务

线程池关闭的时候,也需要对任务加入队列操作进行额外的协调处理

01、具体措施

JDK内置提供了四种拒绝策略:

AbortPolicy策略:直接抛出异常

线程池默认的拒绝策略;该策略会直接抛出异常,任务不会被执行

CallerRunsPolicy策略:只用调用者所在线程来运行任务

只要线程池未关闭,该策略直接在调用者线程中,运行当前被丢弃的任务,但是,任务提交线程的性能极有可能会急剧下降

DiscardOldestPolicy策略:丢弃队列中即将执行的任务,并执行当前任务

该策略将丢弃最老的一个请求,也就是就是即将被执行的一个任务,并尝试再次提交当前任务

DiscardPolicy策略:不处理,直接丢弃

该策略默默地丢弃无法处理的任务,不予任何处理。如果允许任务丢失,这可能是最好的一个建议方案

02、自定义扩展

以上JDK内置的四中拒绝策略均实现了RejectExecutionHandler接口,我们以AbortPolicy在JDK中的实现进行说明,如代码1所示。

1

/**

* A handler for rejected tasks that throws a

* {@code RejectedExecutionException}.

*/

publicstaticclassAbortPolicyimplementsRejectedExecutionHandler {

/**

* Creates an {@code AbortPolicy}.

*/

publicAbortPolicy() { }

/**

* Always throws RejectedExecutionException.

*

*@paramr the runnable task requested to be executed

*@parame the executor attempting to execute this task

*@throwsRejectedExecutionException always

*/

publicvoidrejectedExecution(Runnable r, ThreadPoolExecutor e) {

thrownewRejectedExecutionException("Task "+ r.toString() +" rejected from "+e.toString());

}

}

如果以上策略任无法满足实际应用需求,可以自己扩展实现RejectExecutionHandler接口;老铁们可按照代码1的编程模式实现自定义的拒绝策略,此处不再赘述。

03、小结

划重点

线程池有一个任务队列,用于缓存所有待处理的任务,一旦开始处理这些任务,这些任务就将从上述任务队列中进行删除;为此,在任务队列长度有限的情况下,就会出现新任务的拒绝处理问题,需要一种策略来处理这种应该加入队列却因队列已满无法加入的情况。

线程池提供四种拒绝策略;如果这些无法满足用户需求,可扩展标准接口,实现自定义的拒绝策略。

【参考资料】

1 Java多线程编程实战指南, 黄文海, 中国工信出版集团。

2 实战Java高并发程序设计, 葛一鸣,郭超, 中国工信出版集团,电子工业出版社。

3 Java并发编程从入门到精通,张振华,清华大学出版社。

程序员Chatbook