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层每层解决不同的问题,可以按需取用,相当方便. ...
随机推荐
- 【BZOJ3589】动态树 树链剖分+线段树
Description 别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件 事件0: 这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子. 事件1: 小明希望你 ...
- 洛谷P3122 [USACO15FEB]圈住牛Fencing the Herd(计算几何+CDQ分治)
题面 传送门 题解 题目转化一下就是所有点都在直线\(Ax+By-C=0\)的同一侧,也就可以看做所有点代入\(Ax+By-C\)之后的值符号相同,我们只要维护每一个点代入直线之后的最大值和最小值,看 ...
- 洛谷P3236 [HNOI2014]画框(最小乘积KM)
题面 传送门 题解 我似乎连\(KM\)都不会打啊→_→ 和bzoj2395是一样的,只不过把最小生成树换成\(KM\)了.因为\(KM\)跑的是最大权值所以取个反就行了 //minamoto #in ...
- 关于C语言中printf函数“输出歧视”的问题
目录 关于C语言中printf函数"输出歧视"的问题 问题描述 探索问题原因 另一种研究方法 问题结论 关于C语言中printf函数"输出歧视"的问题 问题描述 ...
- Python3之configparser模块
1. 简介 configparser用于配置文件解析,可以解析特定格式的配置文件,多数此类配置文件名格式为XXX.ini,例如mysql的配置文件.在python3.X中 模块名为configpars ...
- CF165D Beard Graph
$ \color{#0066ff}{ 题目描述 }$ 给定一棵树,有m次操作. 1 x 把第x条边染成黑色 2 x 把第x条边染成白色 3 x y 查询x~y之间的黑边数,存在白边输出-1 \(\co ...
- Svn安装成功后的操作
一.服务器端创建目录 在Svn服务器端创建一个用来保存客户端提交文件的文件夹 (我的路径是d:/Svn/App/book) 首先将Svn的服务端安装目录/bin 进行环境配置,以下操作是在进行环境配置 ...
- 【Leedcode】Insertion Sort List
Sort a linked list using insertion sort. /** * Definition for singly-linked list. * struct ListNode ...
- Win7电脑开机无法正常启动只能进入安全模式解决方式
我们先尝试在开机的时候按F8进入安全模式,进入到安全模式后一次打开“控制面板”-“程序与功能”,然后将卡巴斯基卸载[ http://jingyan.baidu.com/article/ff42efa9 ...
- C++_类入门5-智能指针模板类
智能指针是行为类似于指针的类对象,但这种对象还有其他功能. 本节介绍三个可帮助管理动态内存分配的智能指针模板(auto_ptr.unique_ptr和shared_ptr). void remodel ...