ThreadPoolExecutor(上篇)
Java有两个线程池类:ThreadPoolExecutor和ScheduledThreadPoolExecutor,继承AbstractExecutorService类,AbstractExecutorService类实现了ExecutorService接口。Java API提供了Executors工厂类来帮助创建各种线程池。

ThreadPoolExecutor 构造方法
ThreadPoolExecutor 的构造方法如下:
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
- corePoolSize:指定了线程池中的线程数量。
- maximumPoolSize:指定了线程池中的最大线程数量。
- keepAliveTime:当前线程池数量超过 corePoolSize 时,多余的空闲线程的存活时间,即多
次时间内会被销毁。 - unit:keepAliveTime 的单位。
- workQueue:任务队列,被提交但尚未被执行的任务。
- threadFactory:线程工厂,用于创建线程,一般用默认的即可。
- handler:拒绝策略,当任务太多来不及处理,如何拒绝任务。
ThreadPoolExecutor工作流程

1、线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面
有任务,线程池也不会马上执行它们。
2、当调用 execute() 方法添加一个任务时,线程池会做如下判断:
a、如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;
b、如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列;
c、如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要
创建非核心线程立刻运行这个任务;
d、如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池
会抛出异常 RejectExecutionException。
3、当一个线程完成任务时,它会从队列中取下一个任务来执行。
4、当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运
行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它
最终会收缩到 corePoolSize 的大小。
现代码实验下:
当池中正在运行的线程数(包括空闲线程)小于corePoolSize时,新建线程执行任务。
public class Exam13_1 {
public static void main(String[] args) {
ExecutorService executor = new ThreadPoolExecutor(2, 3, 1, TimeUnit.HOURS,
new LinkedBlockingQueue<>(1));
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
};
//任务1
executor.submit(runnable);
//任务2
executor.submit(runnable);
}
}
实验结果

从实验结果上可以看出,当执行任务1的线程(thread-1)执行完成之后,任务2并没有去复用thread-1而是新建线程(thread-2)去执行任务。
当池中正在运行的线程数大于等于corePoolSize时,新插入的任务进入workQueue排队(如果workQueue长度允许),等待空闲线程来执行。
public class Exam13_1 {
public static void main(String[] args) {
ExecutorService executor = new ThreadPoolExecutor(2, 3, 1, TimeUnit.HOURS,
new LinkedBlockingQueue<>(1));
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
};
//任务1
executor.submit(runnable);
//任务2
executor.submit(runnable);
//任务3
executor.submit(runnable);
}
}

从实验结果上看,任务3会等待任务1执行完之后,有了空闲线程,才会执行。并没有新建线程执行任务3,这时maximumPoolSize=3这个参数不起作用
当队列里的任务数达到上限,并且池中正在运行的线程数小于maximumPoolSize,对于新加入的任务,新建线程。
public class Exam13_1 {
public static void main(String[] args) {
ExecutorService executor = new ThreadPoolExecutor(2, 3, 1, TimeUnit.HOURS,
new LinkedBlockingQueue<>(1));
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
};
//任务1
executor.submit(runnable);
//任务2
executor.submit(runnable);
//任务3
executor.submit(runnable);
//任务4
executor.submit(runnable);
}
}

从实验结果上看,当任务4进入队列时发现队列的长度已经到了上限,所以无法进入队列排队,而此时正在运行的线程数(2)小于maximumPoolSize所以新建线程执行该任务。
当队列里的任务数达到上限,并且池中正在运行的线程数等于maximumPoolSize,对于新加入的任务,执行拒绝策略(线程池默认的拒绝策略是抛异常)。
public class Exam13_1 {
public static void main(String[] args) {
ExecutorService executor = new ThreadPoolExecutor(2, 3, 1, TimeUnit.HOURS,
new LinkedBlockingQueue<>(1));
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
};
//任务1
executor.submit(runnable);
//任务2
executor.submit(runnable);
//任务3
executor.submit(runnable);
//任务4
executor.submit(runnable);
//任务5
executor.submit(runnable);
}
}

实验结果分析:当任务5加入时,队列达到上限,池内运行的线程数达到最大,故执行默认的拒绝策略,抛异常。
ThreadPoolExecutor(上篇)的更多相关文章
- Android线程管理之ThreadPoolExecutor自定义线程池
前言: 上篇主要介绍了使用线程池的好处以及ExecutorService接口,然后学习了通过Executors工厂类生成满足不同需求的简单线程池,但是有时候我们需要相对复杂的线程池的时候就需要我们自己 ...
- 系统间通信(3)——IO通信模型和JAVA实践 上篇
来源:http://blog.csdn.net/yinwenjie 1.全文提要 系统间通信本来是一个很大的概念,我们首先重通信模型开始讲解.在理解了四种通信模型的工作特点和区别后,对于我们后文介绍搭 ...
- ThreadPoolExecutor使用和思考(上)-线程池大小设置与BlockingQueue的三种实现区别
工作中多处接触到了ThreadPoolExecutor.趁着现在还算空,学习总结一下. 前记: jdk官方文档(javadoc)是学习的最好,最权威的参考. 文章分上中下.上篇中主要介绍ThreadP ...
- ThreadPoolExecutor的应用和实现分析(中)—— 任务处理相关源码分析 线程利用(转)
前面一篇文章从Executors中的工厂方法入手,已经对ThreadPoolExecutor的构造和使用做了一些整理.而这篇文章,我们将接着前面的介绍,从源码实现上对ThreadPoolExecuto ...
- ThreadPoolExecutor(下篇)
上篇写到了ThreadPoolExecutor构造方法前4个参数int corePoolSize.int maximumPoolSize,.long keepAliveTime.TimeUnit un ...
- 看看C# 6.0中那些语法糖都干了些什么(上篇)
今天没事,就下了个vs2015 preview,前段时间园子里面也在热炒这些新的语法糖,这里我们就来看看到底都会生成些什么样的IL? 一:自动初始化属性 确实这个比之前的版本简化了一下,不过你肯定很好 ...
- 并发包的线程池第一篇--ThreadPoolExecutor执行逻辑
学习这个很长时间了一直没有去做个总结,现在大致总结一下并发包的线程池. 首先,任何代码都是解决问题的,线程池解决什么问题? 如果我们不用线程池,每次需要跑一个线程的时候自己new一个,会导致几个问题: ...
- ThreadPoolExecutor源码学习(1)-- 主要思路
ThreadPoolExecutor是JDK自带的并发包对于线程池的实现,从JDK1.5开始,直至我所阅读的1.6与1.7的并发包代码,从代码注释上看,均出自Doug Lea之手,从代码上看JDK1. ...
- ThreadPoolExecutor源码学习(2)-- 在thrift中的应用
thrift作为一个从底到上除去业务逻辑代码,可以生成多种语言客户端以及服务器代码,涵盖了网络,IO,进程,线程管理的框架,着实庞大,不过它层次清晰,4层每层解决不同的问题,可以按需取用,相当方便. ...
随机推荐
- [AGC005C]Tree Restoring 构造
Description 给出一个数组a,要求构造一颗树,使节点x距离最远的点的距离为\(a_x\). Input 第一行一个正整数NN(2≤N≤1002≤N≤100) 接下来一行,有NN个 ...
- HDU6336-2018ACM暑假多校联合训练4-1005-Problem E. Matrix from Arrays-前缀和
题意是给了一种矩阵的生成方式 让你求两个左边之间的矩阵里面的数加起来的和(不是求矩阵的值) 没看标程之前硬撸写了160行 用了前缀和以后代码量缩短到原来的1/3 根据规律可以推导出这个矩阵是在不断重复 ...
- nginx公网IP无法访问浏览器
配置服务器时候发现的问题,真的是搜肠刮肚的找答案,找一下午,终于找到了答案. 一.开始找原因 在浏览器输入:http://ip,正常的话,会有页面,welcome to nginx 我这里是浏览器访问 ...
- 老男孩Day14作业:堡垒机
一.作业需求: 1.业务需求 兼顾业务安全目标与用户体验,堡垒机部署后,不应使用户访问业务系统的访问变的复杂,否则工作将很难推进,因为没人喜欢改变现状,尤其是改变后生活变得更艰难 保证堡垒机稳 ...
- 记录一些好用的iOS第三方库
CBStoreHouseRefreshControl:一个效果很酷炫的下拉刷新控件. ZLSwipeableView:ZLSwipeableView是一个方便做出卡片效果的UI库,支持各种卡片的滑动效 ...
- docker 安装 postgresql
docker拉去镜像以及配置生成容器的步骤几乎和之前的nginx安装一样,直接写下面的命令了 1. docker pull postgres 2. docker run --name xf-postg ...
- JS 创建元素的三种方法
1.动态创建元素一 document.write() 例如向页面中输出一个 li 标签 <pre class="html" name="code"> ...
- CoreML的学习
在苹果官网下载模型model 链接: https://developer.apple.com/machine-learning/
- Java 实现发送邮件
javax.mail.AuthenticationFailedException: 530 Error: A secure connection is requiered(such as ssl). ...
- Mysql相关操作:
允许root用户远程访问:https://www.cnblogs.com/davidgu/p/3706663.html; 用户的添加删除管理: https://www.cnblogs.com/hzd2 ...