线程池的四种拒绝策略
一、前言
线程池,相信很多人都有用过,没用过相信的也有学习过。但是,线程池的拒绝策略,相信知道的人会少许多。
二、四种线程池拒绝策略
当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize时,如果还有任务到来就会采取任务拒绝策略,通常有以下四种策略:
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。 ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常。 ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务 ThreadPoolExecutor.CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务
三、线程池默认的拒绝策略
既然有四种拒绝策略可以选择,那么线程池的默认拒绝策略是什么呢?查看
java.util.concurrent.ThreadPoolExecutor类的源码,我们可以看到:
- /**
- * The default rejected execution handler
- */
- private static final RejectedExecutionHandler defaultHandler =
- new AbortPolicy();
线程池的默认拒绝策略为AbortPolicy,即丢弃任务并抛出RejectedExecutionException异常。我们可以通过代码来验证这一点,现有如下代码:
public class ThreadPoolTest {
public static void main(String[] args) {
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(100);
ThreadFactory factory = r -> new Thread(r, "test-thread-pool");
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5,
0L, TimeUnit.SECONDS, queue, factory);
while (true) {
executor.submit(() -> {
try {
System.out.println(queue.size());
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
}
}
这里是一个默认的线程池,没有设置拒绝策略,设置了最大线程队列是100。运行代码:
结果是符合预期的,这也证明了线程池的默认拒绝策略是ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
四、设置线程池拒绝策略
如果我们想要根据实际业务场景需要,设置其他的线程池拒绝策略,可以通过ThreadPoolExecutor重载的构造方法进行设置:
现在的开发中,相信大家都有使用spring,其实我们也可以通过spring提供的org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor构建线程池。如下:
@Configuration
public class TaskExecutorConfig implements AsyncConfigurer {
/**
* Set the ThreadPoolExecutor's core pool size.
*/
private static final int CORE_POOL_SIZE = 5;
/**
* Set the ThreadPoolExecutor's maximum pool size.
*/
private static final int MAX_POOL_SIZE = 5;
/**
* Set the capacity for the ThreadPoolExecutor's BlockingQueue.
*/
private static final int QUEUE_CAPACITY = 1000;
/**
* 通过重写getAsyncExecutor方法,制定默认的任务执行由该方法产生
* <p>
* 配置类实现AsyncConfigurer接口并重写getAsyncExcutor方法,并返回一个ThreadPoolTaskExevutor
* 这样我们就获得了一个基于线程池的TaskExecutor
*/
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(CORE_POOL_SIZE);
taskExecutor.setMaxPoolSize(MAX_POOL_SIZE);
taskExecutor.setQueueCapacity(QUEUE_CAPACITY);
taskExecutor.initialize();
taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
return taskExecutor;
}
}
五、拒绝策略场景分析
(1)AbortPolicy
AbortPolicy
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
A handler for rejected tasks that throws a {@code RejectedExecutionException}.
这是线程池默认的拒绝策略,在任务不能再提交的时候,抛出异常,及时反馈程序运行状态。如果是比较关键的业务,推荐使用此拒绝策略,这样子在系统不能承载更大的并发量的时候,能够及时的通过异常发现。
(2)DiscardPolicy
ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常。如果线程队列已满,则后续提交的任务都会被丢弃,且是静默丢弃。
A handler for rejected tasks that silently discards therejected task.
使用此策略,可能会使我们无法发现系统的异常状态。建议是一些无关紧要的业务采用此策略。例如,本人的博客网站统计阅读量就是采用的这种拒绝策略。
(3)DiscardOldestPolicy
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务。
A handler for rejected tasks that discards the oldest unhandled request and then retries {@code execute}, unless the executor is shut down, in which case the task is discarded.
此拒绝策略,是一种喜新厌旧的拒绝策略。是否要采用此种拒绝策略,还得根据实际业务是否允许丢弃老任务来认真衡量。
(4)CallerRunsPolicy
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
- A handler for rejected tasks that runs the rejected task directly in the calling thread of the {@code execute} method, unless the executor has been shut down, in which case the task is discarded.
如果任务被拒绝了,则由调用线程(提交任务的线程)直接执行此任务,我们可以通过代码来验证这一点:
把之前的代码修改如下:
- public static void main(String[] args) {
- BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(10);
- ThreadFactory factory = r -> new Thread(r, "test-thread-pool");
- ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5,
- 0L, TimeUnit.SECONDS, queue, factory, new ThreadPoolExecutor.CallerRunsPolicy());
- for (int i = 0; i < 1000; i++) {
- executor.submit(() -> {
- try {
- System.out.println(Thread.currentThread().getName() + ":执行任务");
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- });
- }
- }
把队列最大值改为10,打印输出线程的名称。执行结果如下:
通过结果可以看到,主线程main也执行了任务,这正说明了此拒绝策略由调用线程(提交任务的线程)直接执行被丢弃的任务的。
六、总结
本文介绍和演示了四种线程池拒绝策略,具体使用哪种策略,还得根据实际业务场景才能做出抉择。
线程池的四种拒绝策略相关推荐
- Java多线程学习七:线程池的 4 种拒绝策略和 6 种常见的线程池
以便在必要的时候按照我们的策略来拒绝任务,那么拒绝任务的时机是什么呢?线程池会在以下两种情况下会拒绝新提交的任务. 第一种情况是当我们调用 shutdown 等方法关闭线程池后,即便此时可能线程池内部 ...
- Java 线程池 ThreadPoolExecutor 八种拒绝策略浅析
前言 谈到 Java 的线程池最熟悉的莫过于 ExecutorService 接口了,jdk1.5 新增的 java.util.concurrent 包下的这个 api,大大的简化了多线程代码的开发. ...
- 线程池三大方法,七大参数,四种拒绝策略
线程和进程: 进程: 一个程序,是执行程序的一次执行过程. 一个进程往往包含若干个线程,线程是cpu调度和执行的单位. Java默认有2个线程:main.GC 池化技术: 01:程序的运行,本质 :占 ...
- 《Java线程池》:任务拒绝策略
<Java线程池>:任务拒绝策略 转载:https://blog.csdn.net/u010412719/article/details/52132613 在没有分析线程池原理之前先来分析 ...
- java assert使用场景_Java线程池的四种用法与使用场景
一.如下方式存在的问题 new Thread() { @Override public void run() { // 业务逻辑 }}.start(); 1.首先频繁的创建.销毁对象是一个很消耗性能的 ...
- 第二十八期:Java线程池的四种用法与使用场景
线程池的作用主要是为了提升系统的性能以及使用率.文章刚开始就提到,如果我们使用最简单的方式创建线程,如果用户量比较大,那么就会产生很多创建和销毁线程的动作,这会导致服务器在创建和销毁线程上消耗的性能可 ...
- newsinglethreadexecutor使用场景_Java线程池的四种用法与使用场景
来源公众号一个程序员的成长 ,作者小涛 一.如下方式存在的问题 new Thread() { @Override public void run() { // 业务逻辑 }}.start(); 1.首 ...
- Java线程池的四种创建方式
Java线程池的四种创建方式 Java使用Thread类来表示线程,所有的线程都是Thread类或者是他的子类.Java有四种方式来创建线程. (1)继承Thread类创建线程 (2)实现Runnab ...
- 关于线程池的五种实现方式,七大参数,四种拒绝策略
一.池化技术之线程池 实现线程池视频讲解,附源码:「链接」 什么是池化技术?简单来说就是优化资源的使用,我准备好了一些资源,有人要用就到我这里拿,用完了就还给我.而一个比较重要的的实现就是线程池.那么 ...
最新文章
- 奇异值分解与最小二乘问题 线性回归
- 单元测试中使用mock最好不要使用easymock而应该使用powermock
- 单片机实用工具大全,超级赞,工程师必备!
- 【MySQL】4、Select查询语句
- [上架] iOS 上架更新版本号建议
- 30. 包含min函数的栈
- java poi 导出excel 速度慢_java POI技术之导出数据优化(15万条数据1分多钟)
- sql azure 语法_使用Azure门户监视安装了SQL Server的Azure计算机
- 十大 Photoshop 组合快捷键杀手锏
- AS1.3 及其以上预览版新插件-实验版(NDK)
- gif 格式图片详细解析
- XJOI 9291 Hello OI
- windows共享 无法访问
- 微信开发工具,字体如何调整的大一点?
- 《AutoCAD 2014中文版超级学习手册》——第2章 图层设置 2.1 设置图层
- kd树 python实现_Python - KDTree 实现
- iis,w3wp一直出现WerFault.exe应用程序错误
- DSP广告精准投放平台如何快速提升品牌知名度
- 毕业论文的页眉页脚?奇偶页不同?前言作为第一页?……?这样弄!
- DAY2-Ubuntu主题与终端的美化
热门文章
- 【图像处理】数字图像处理笔记
- PL/SQL Developer 开发工具技巧总结
- 关于disabled属性
- 如何才能写出好的APP新闻报道及软文?
- 寿命计算器测试软件,你还能活多久?这个“寿命计算器”可以给出答案
- [手游屌丝研究] 手游IP市场调查:授权金似北京房价【一】
- Java并发编程的艺术pdf
- telnet重启计算机,win7系统重启Telnet命令的操作方法
- 60道Python常见面试题,做对80% Offer任你挑!
- ThinkPad T460p笔记本中Win10+Ubuntu17.04双系统安装方法(UEFI引导模式)