线程池的拒绝策略
时间:2022-07-28
本文章向大家介绍线程池的拒绝策略,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
线程池
欢迎来到狗哥多线程系列连载。本篇是线程相关的第七篇,前六篇分别是:
线程池的拒绝策略
因为线程池是在提交任务时根据情况执行拒绝策略的,而提交任务涉及两个方法:execute 和 sumbit。在说拒绝策略之前,先谈谈这两方法的区别。
什么时候执行拒绝策略?
先看看 submit 的源码:可以看到它最终还是调用 execute 方法。与 execute 的区别就是:可以接收线程池执行的返回值,而 execute () 不能接收返回值。
public Future < ? > submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture < Void > ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
再看 execute 源码,注释写得很清楚了,简单说下,分为三步:
- 当工作线程小于核心线程时,直接提交执行就完事了。
- 线程池处于运行状态,提交任务到队列。再次检查状态,若非运行状态,则移除任务并执行拒绝策略;否则,创建线程执行任务。
- 线程池处于非运行状态或者启动线程执行失败,则执行拒绝策略。
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
// 当前工作的线程数小于核心线程数
if (workerCountOf(c) < corePoolSize) {
// 创建新的线程执行此任务
if (addWorker(command, true))
return;
c = ctl.get();
}
// 检查线程池是否处于运行状态,如果是则把任务添加到队列
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
// 再次检查线程池是否处于运行状态,防止在第一次校验通过后线程池关闭
// 如果是非运行状态,则将刚加入队列的任务移除,并执行拒绝策略
if (!isRunning(recheck) && remove(command))
reject(command);
// 如果线程池的线程数为 0 时(当 corePoolSize 设置为 0 时会发生)
// 新建线程执行任务
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
// 核心线程都在忙且队列都已爆满,尝试新启动一个线程执行失败
} else if (!addWorker(command, false))
// 执行拒绝策略
reject(command);
}
Java 提供的拒绝策略
Java 给我们提供了拒绝策略,创建线程池时就可以指定拒绝策略,比如:
newThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS, new LinkedBlockingQueue < > (),
new ThreadPoolExecutor.AbortPolicy());
当然,你也可以自己实现~
上面了解了拒绝策略的执行时机,再来看看 Java 给我们提供的拒绝策略。分为四种,关系如下:
拒绝策略.png
逐个聊聊它们的特点:
- AbortPolicy:线程池默认的拒绝策略(不值当就是它),拒绝任务时,直接抛出一个类型为 RejectedExecutionException 的运行时异常。你可以捕获逐个异常并根据自己的业务进行处理。
- DiscardPolicy:这种非常粗暴,拒绝任务时不通知你。相当于,这个任务提没有提交成功,你是不知道的,非常不友好。
- DiscardOldestPolicy:看名字就知道跟第二种差不多,一样不通知。区别在于:它抛弃的任务通常是队列的头结点,也就是存活时间最长的任务。
- CallerRunsPolicy:这种最友好。线程池没能力执行任务,就把这个任务交于提交任务的线程执行,也就是谁提交谁执行(并不一定是主线程提交任务)。这样做有两点好处:一是新提交任务不被丢弃,不会造成数据丢失;二是因为谁提交谁执行,当任务执行耗时比较长,它也就不会去提交任务,减缓任务提交的速度,线程池中的线程可以趁机执行掉一部分任务,相当于给线程提供一个缓冲期。
总结
本文从源码分析了拒绝策略的执行时机并详细介绍了 Java 提供的四种拒绝策略,相信大家看完会有所收获。选用哪种线程池是根据你自己的业务而定的,实践出真知。
巨人的肩膀
- https://kaiwu.lagou.com/course/courseInfo.htm?courseId=16#/detail/pc?id=239
-END-
如果看到这里,说明你喜欢这篇文章,请转发、点赞。微信搜索「一个优秀的废人」,关注后回复「 1024」送你一套完整的 java 教程(包括视频)。回复「 电子书」送你Java、C、C++、Linux、Go、Python、数据库、前端、计算机基础、人工智能、数据结构与算法、设计模式以及面试相关电子书 。
教程节选
- silverlight:RadMaskedTextBox设置MaskType="Numeric"及Mask="n"时的一个bug
- 微信里面最神秘的功能,你知道吗?
- 以大数据之名,变身!——In big data we trust
- 90%家长都不知道关于少儿编程的这些疑题!
- 常用SQL语句和语法汇总
- Python学习笔记1——斐波那契数列
- 视觉传感器几大技术要点详解!
- Spark之搜狗日志查询实战
- 区块链与数字货币是什么关系呢?
- 保存数据到MySql数据库——我用scrapy写爬虫(二)
- 人工智能将取代人类?危机亦或是新的机遇
- 大数据驱动的未来网络:体系架构与应用场景(下)网络架构与场景详解
- 冷静点,NVIDIA 禁止 Geforce 进数据中心想限制的并不是深度学习
- 智能机器人崛起背后的中国力量
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法