ThreadPoolExecutor之RejectedExecutionHandler
最近工作种常用到ThreadPoolExecutor这个对象, 这是一个并发编程中非常常用的对象。因为和并发编程相关所以它存在于java.util.concurrent这包中。
创建这个对象的基本方法如下:

今天主要想研究一下最后一个参数RejectedExecutionHandler对整个线程池的影响。首先写出需要用到测试代码如下:
import java.io.Serializable;
import java.util.concurrent.*; public class ThreadPoolExecutorTest {
private static int produceTaskSleepTime = 1000; // 一秒add一个任务
private static int consumeTaskSleepTime = 60000; //每个任务停留10秒这样结果更明显清楚
private static BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(2); //缓存队列数
private static int produceTaskMaxNumber = 51; //总线程数 private static int corePoolSize = 2; //
private static int maximumPoolSize = 4;
private static int keepAliveTime = 5; public static void main(String[] args) {
ThreadPoolExecutor threadPoolExcutor = new ThreadPoolExecutor(corePoolSize,
maximumPoolSize,
keepAliveTime,
TimeUnit.SECONDS,
queue,
new ThreadPoolExecutor.DiscardPolicy()); //调整策略 for(int i=1; i< produceTaskMaxNumber;i++){
try{
String work = "Task@ " + i;
System.out.println("put : " + work);
threadPoolExcutor.execute(new ThreadPoolTask(work)); System.out.println("BlockQueue Size is " + queue.size()); //打印出缓存队列中线程数
//等待一段时间方便看清楚线程处理顺序
Thread.sleep(produceTaskSleepTime);
}catch (Exception e){
e.printStackTrace();
}
} } public static class ThreadPoolTask implements Runnable, Serializable{
private static final long serialVersionUID = 0;
private Object threadPoolTaskData; ThreadPoolTask(Object work){
this.threadPoolTaskData = work;
} @Override
public void run() {
System.out.println("start............" + threadPoolTaskData); //标记任务开始
try {
Thread.sleep(consumeTaskSleepTime);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("end.............." + threadPoolTaskData); //标记任务结束
threadPoolTaskData = null;
} public Object getTask(){
return this.threadPoolTaskData;
}
}
}
我的想法是模拟50个任务,每个任务执行60s,这样就可以不断有任务阻塞到缓存队列,并在一定时间内达到线程池最大线程数,进而发现不同拒绝策略是在线程数超出线程池最大允许数量后是如何处理。
1.DiscardPolicy
put : Task@ 1
BlockQueue Size is 0
start............Task@ 1
put : Task@ 2
BlockQueue Size is 0
start............Task@ 2
put : Task@ 3
BlockQueue Size is 1
put : Task@ 4
BlockQueue Size is 2
put : Task@ 5
BlockQueue Size is 2
start............Task@ 5
put : Task@ 6
BlockQueue Size is 2
start............Task@ 6
put : Task@ 7
BlockQueue Size is 2
..........
..........
put : Task@ 50
BlockQueue Size is 2
end..............Task@ 1
start............Task@ 3
end..............Task@ 2
start............Task@ 4
end..............Task@ 5
end..............Task@ 6
end..............Task@ 3
end..............Task@ 4
从结果可以看出,线程装载顺序是
核心线程数(1,2满)->缓存队列数(3,4 满)->最大线程数(5,6满)->不执行。
结论:大于最大线程数以后的任务完全不执行。
2.AbortPolicy
put : Task@ 7
java.util.concurrent.RejectedExecutionException: Task com.dangkei.ThreadPoolExecutorTest$ThreadPoolTask@7cf10a6f rejected from java.util.concurrent.ThreadPoolExecutor@2ff4f00f[Running, pool size = 4, active threads = 4, queued tasks = 2, completed tasks = 0]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.reject(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.execute(Unknown Source)
at com.dangkei.ThreadPoolExecutorTest.main(ThreadPoolExecutorTest.java:28)
结论:运行结果前后相同但是 在put Task 7时,也就是超过最大线程数后每个线程都抛出RejectedExecutionException
3.DiscardOldestPolicy
put : Task@ 1
BlockQueue Size is 0
start............Task@ 1
put : Task@ 2
BlockQueue Size is 0
start............Task@ 2
put : Task@ 3
BlockQueue Size is 1
put : Task@ 4
BlockQueue Size is 2
put : Task@ 5
BlockQueue Size is 2
start............Task@ 5
put : Task@ 6
BlockQueue Size is 2
start............Task@ 6
put : Task@ 7
BlockQueue Size is 2
put : Task@ 8
BlockQueue Size is 2
......
......
put : Task@ 49
BlockQueue Size is 2
put : Task@ 50
BlockQueue Size is 2
end..............Task@ 1
start............Task@ 49
end..............Task@ 2
start............Task@ 50
end..............Task@ 5
end..............Task@ 6
end..............Task@ 49
end..............Task@ 50
开始觉得这个结果比较奇怪,后来反应过来。 所谓1,2 ,5,6最终都执行结束了但是3,4线程没有开始。最后还有49,50也都结束.
结论,废弃最旧的线程是废弃掉缓存队列里最旧的线程对 核心队列(corePoolSize),和 (核心队列+缓存队列)< 线程队列 < 最大线程数 中间这部分线程(5,6 )也没影响。
由于新的线程任务不断替换掉 缓存队列里的任务, 所以 位于 blockingqueue里的任务始终无法执行。 只有最后两个线程(499,50) 没有被新的任务替换正常执行了。
4.CallerRunsPolicy
put : Task@ 1
BlockQueue Size is 0
start............Task@ 1
put : Task@ 2
BlockQueue Size is 0
start............Task@ 2
put : Task@ 3
BlockQueue Size is 1
put : Task@ 4
BlockQueue Size is 2
put : Task@ 5
BlockQueue Size is 2
start............Task@ 5
put : Task@ 6
BlockQueue Size is 2
start............Task@ 6
put : Task@ 7
start............Task@ 7
end..............Task@ 1
start............Task@ 3
end..............Task@ 2
start............Task@ 4
end..............Task@ 5
end..............Task@ 6
end..............Task@ 7
BlockQueue Size is 0
put : Task@ 8
BlockQueue Size is 1
start............Task@ 8
put : Task@ 9
start............Task@ 9
BlockQueue Size is 0
put : Task@ 10
BlockQueue Size is 1
put : Task@ 11
BlockQueue Size is 2
put : Task@ 12
start............Task@ 12
end..............Task@ 3
start............Task@ 10
end..............Task@ 4
start............Task@ 11
end..............Task@ 8
end..............Task@ 9
end..............Task@ 12
BlockQueue Size is 0
put : Task@ 13
BlockQueue Size is 1
start............Task@ 13
put : Task@ 14
BlockQueue Size is 1
put : Task@ 15
BlockQueue Size is 2
put : Task@ 16
BlockQueue Size is 2
start............Task@ 16
put : Task@ 17
start............Task@ 17
end..............Task@ 10
start............Task@ 14
end..............Task@ 11
start............Task@ 15
end..............Task@ 13
end..............Task@ 16
end..............Task@ 17
BlockQueue Size is 0
put : Task@ 18
BlockQueue Size is 0
start............Task@ 18
put : Task@ 19
BlockQueue Size is 1
put : Task@ 20
BlockQueue Size is 2
put : Task@ 21
BlockQueue Size is 2
start............Task@ 21
put : Task@ 22
start............Task@ 22
end..............Task@ 14
start............Task@ 19
end..............Task@ 15
start............Task@ 20
end..............Task@ 18
end..............Task@ 21
end..............Task@ 22
BlockQueue Size is 0
put : Task@ 23
BlockQueue Size is 1
start............Task@ 23
put : Task@ 24
BlockQueue Size is 1
put : Task@ 25
BlockQueue Size is 2
put : Task@ 26
BlockQueue Size is 2
start............Task@ 26
put : Task@ 27
start............Task@ 27
end..............Task@ 19
start............Task@ 24
end..............Task@ 20
start............Task@ 25
end..............Task@ 23
end..............Task@ 26
end..............Task@ 27
BlockQueue Size is 0
put : Task@ 28
start............Task@ 28
BlockQueue Size is 0
put : Task@ 29
BlockQueue Size is 1
start............Task@ 29
put : Task@ 30
BlockQueue Size is 1
put : Task@ 31
BlockQueue Size is 2
put : Task@ 32
start............Task@ 32
end..............Task@ 24
start............Task@ 30
end..............Task@ 25
start............Task@ 31
end..............Task@ 28
end..............Task@ 29
end..............Task@ 32
BlockQueue Size is 0
put : Task@ 33
BlockQueue Size is 1
start............Task@ 33
put : Task@ 34
BlockQueue Size is 1
put : Task@ 35
BlockQueue Size is 2
put : Task@ 36
BlockQueue Size is 2
start............Task@ 36
put : Task@ 37
start............Task@ 37
end..............Task@ 30
start............Task@ 34
end..............Task@ 31
start............Task@ 35
end..............Task@ 33
end..............Task@ 36
end..............Task@ 37
BlockQueue Size is 0
put : Task@ 38
start............Task@ 38
BlockQueue Size is 0
put : Task@ 39
BlockQueue Size is 1
put : Task@ 40
BlockQueue Size is 2
put : Task@ 41
BlockQueue Size is 2
start............Task@ 41
put : Task@ 42
start............Task@ 42
end..............Task@ 34
start............Task@ 39
end..............Task@ 35
start............Task@ 40
end..............Task@ 38
end..............Task@ 41
end..............Task@ 42
BlockQueue Size is 0
put : Task@ 43
start............Task@ 43
BlockQueue Size is 0
put : Task@ 44
BlockQueue Size is 1
put : Task@ 45
BlockQueue Size is 2
put : Task@ 46
BlockQueue Size is 2
start............Task@ 46
put : Task@ 47
start............Task@ 47
end..............Task@ 39
start............Task@ 44
end..............Task@ 40
start............Task@ 45
end..............Task@ 43
end..............Task@ 46
end..............Task@ 47
BlockQueue Size is 0
put : Task@ 48
BlockQueue Size is 1
start............Task@ 48
put : Task@ 49
BlockQueue Size is 1
put : Task@ 50
BlockQueue Size is 2
end..............Task@ 44
start............Task@ 49
end..............Task@ 45
start............Task@ 50
end..............Task@ 48
这次贴出的是比较完整的打印结果:
结论:可以看到使用这种策略是不会丢失任何任务或者抛出任何异常的。 适应于对数据要求比较严谨的任务。

从这段结果还有个有意思的发现 其实使用这种策略是可以同时执行最大线程数+1个线程。
通过这次实验得到以下总结:
假设我们可以把线程池执行看成三个队列, 核心执行队列, 缓存队列, 最大执行队列。 缓存队列不是执行队列。
一. 它们的装载顺序时这样的。
核心-缓存-最大。
二. 但是执行优先级这样的
核心-最大(然后缓存在所有线程中的任务执行完后进行补充)
三. DiscardPolicy策略
超出最大线程数后的任务将都被废弃不会加入到缓存队列,不抛异常。
四. AbordPolicy策略
超出最大线程数后的任务将被废弃,抛出异常。
五. DiscardOldestPolicy策略
超出最大线程数后的任务将顶替缓存队列中最早的任务。不抛异常但是被顶替掉的任务将丢失不执行。
六. CallerRunsPolicy策略
超出最大线程数后的任务将进行缓存队列等待,缓存队列所有任务输送给执行队列完毕清空后,新任务进入缓存队列。
以上属于个人理解, 有不对的地方请指正。 希望对大家学习能有帮助。
ThreadPoolExecutor之RejectedExecutionHandler的更多相关文章
- 自定义ThreadPoolExecutor带Queue缓冲队列的线程池 + JMeter模拟并发下单请求
.原文:https://blog.csdn.net/u011677147/article/details/80271174 拓展: https://github.com/jwpttcg66/GameT ...
- java线程池ThreadPoolExecutor类使用详解
在<阿里巴巴java开发手册>中指出了线程资源必须通过线程池提供,不允许在应用中自行显示的创建线程,这样一方面是线程的创建更加规范,可以合理控制开辟线程的数量:另一方面线程的细节管理交给线 ...
- 如何让ThreadPoolExecutor更早地创建非核心线程
最近在项目中遇到一个需要用线程池来处理任务的需求,于是我用ThreadPoolExecutor来实现,但是在实现过程中我发现提交大量任务时它的处理逻辑是这样的(提交任务还有一个submit方法内部也调 ...
- android 多线程
本章讲述在android开发中,多线程的应用.多线程能够处理耗时的操作并优化程序的性能.本章主要介绍知识点,AsyncTask,Java线程池,ThreadPoolExecutor线程池类.本章案例只 ...
- Android(java)学习笔记267:Android线程池形态
1. 线程池简介 多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力. 假设一个服务器完成一项任务所需时间为:T1 创建线程时间, ...
- Android(java)学习笔记211:Android线程池形态
1. 线程池简介 多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力. 假设一个服务器完成一项任务所需时间为:T1 创建线程时间, ...
- ExecutorService 线程池 (转发)
1.ExecutorService java.util.concurrent.ExecutorService 接口.用来设置线程池并执行多线程任务.它有以下几个方法. Future<?> ...
- Java面试必问之-JUC
JUC:java.util.concurrent (Java并发编程工具类) 代码:D:\JAVA\Java_Learning\Elipse_Project\workspace200301EE\JUC ...
- Java知识点JUC总结
JUC:java.util.concurrent (Java并发编程工具类) 一般面试提问:面向对象和高级语法.Java集合类.Java多线程.JUC 和高并发.Java IO和 NIO 获取多线程的 ...
随机推荐
- WinSCP整合SecureCRT打开终端
使用WinSCP直接操作文件非常方便,但是如果用它来连入SSH进行指令交互就不方便了,使用XShell.SecureCRT.Putty等SSH终端软件敲指令却很不错,于是想能不能将两者结合起来使用.我 ...
- [ZJOI2008]树的统计(树链剖分)
[ZJOI2008]树的统计(luogu) Description 一棵树上有 n 个节点,编号分别为 1 到 n,每个节点都有一个权值 w.我们将以下面的形式来要求你对这棵树完成一些操作: I. C ...
- Linux环境下的network IO
同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案是不同的.所以先限定一下本文的上下文. 本文讨论的背景是Linux环境下的network IO. ...
- 设计模式-03工厂方法模式(Factory Method Pattern)
插曲.简单工厂模式(Simple Factory Pattern) 介绍工厂方法模式之前,先来做一个铺垫,了解一下简单工厂模式,它不属于 GoF 的 23 种经典设计模式,它的缺点是增加新产品时会违背 ...
- Web自动化测试项目搭建(一) 需求与设计
一.项目需求 测试/生产环境更新后,自动化回归测试 项目易于维护和运行 支持多种测试策略 支持可视化测试报告 运行结果,支持多种方式通知相关人员 可定时/触发的方式运行自动化测试用例 二.设计 2.1 ...
- 基于Flask框架搭建视频网站的学习日志(三)之原始web表单
基于Flask框架搭建视频网站的学习日志(三)1.原始Web 表单 本节主要用于体验一下前端后端直接数据的交互,样例不是太完善,下一节会加入Flash处理,稍微完善一下页面 (备注:建议先阅读廖雪峰老 ...
- vmware安装kvm虚拟机
1. 概述 本篇博客主要使用运行在win10专业版上的vmware workstation 15 pro虚拟化软件,安装centos7.7最小化系统,并在centos7上安装kvm虚拟机,实现快速创建 ...
- CodeBlocks 断点调试
启动调试器 1. 一般,调试器的按钮可以在工具栏找到 如果没有,可以从view菜单项中调出 2. 设置断点 使用调试器时需要让程序在需要的位置中断,在启动调试器前设置断点如下,鼠标点击编辑器的左边即可 ...
- asp.net core 2.2升到3.1遇到的问题小记
趁着武汉疫情,在家研究原来2.2的框架升级到3.1的问题,在过程中遇到不少坑,好在放假有的是时间,一个一个解决,现做个简要记录,供大家参考.推荐认真看这篇文章 [https://docs.micros ...
- ThreadLocalRandom ---- 提升Random在大并发下的效率
本博客系列是学习并发编程过程中的记录总结.由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅. 并发编程系列博客传送门 随机数 随机数在科学研究与工程实际中有着极其重要的应用! ...