[Java并发]-04-ThreadPoolExecutor类创建线程池对象和源码分析
来源:互联网 发布:java servlet 文件接口 编辑:程序博客网 时间:2024/06/12 19:27
Executors底层会创建ThreadPoolExecutor或
1 核心构造器
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
- corePoolSize 个线程保持在线程池中,即使他们是空闲的,除非设置allowCoreThreadTimeOut
- maximumPoolSize是池中允许的最大线程数。
- keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
- unit - keepAliveTime 参数的时间单位。
- workQueue - 执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务。
- threadFactory - 执行程序创建新线程时使用的工厂。
- handler - 由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序。
execute(java.lang.Runnable)
中提交时,如果运行的线程少于 corePoolSize,则创建新线程来处理请求,即使其他辅助线程是空闲的。如果设置的 corePoolSize 和 maximumPoolSize 相同,则创建了固定大小的线程池。
如果将 maximumPoolSize 设置为基本的无界值(如 Integer.MAX_VALUE),则允许池适应任意数量的并发任务。
在大多数情况下,核心和最大池大小仅基于构造来设置,不过也可以使用 setCorePoolSize(int)
和setMaximumPoolSize(int)
进行动态更改。
使用 ThreadFactory
创建新线程。如果没有另外说明,则在同一个ThreadGroup
中一律使用Executors.defaultThreadFactory()
创建线程,并且这些线程具有相同的NORM_PRIORITY 优先级和非守护进程状态。通过提供不同的 ThreadFactory,可以改变线程的名称、线程组、优先级、守护进程状态,等等。如果从newThread 返回 null 时ThreadFactory 未能创建线程,则执行程序将继续运行,但不能执行任何任务。
2. 使用SynchronousQueue的线程池
public static class Task implements Callable<String> {private String id;Task(String id) {this.id = "Task-" + id;}@Overridepublic String call() throws Exception {try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(id + " " + Thread.currentThread().getName());return id;}}public static void main(String[] args) {System.out.println("=========main start");final ThreadPoolExecutor exec = new ThreadPoolExecutor(1, 128, 10000L, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(), new ThreadFactory() { @Override public Thread newThread(Runnable r) { return new Thread(r); } });ConcurrencyUtils.printThreadPoolExecutorInfo(exec);for (int i = 0; i < 10; i++) {exec.submit(new Task(String.valueOf(i)));}do {ConcurrencyUtils.printThreadPoolExecutorInfo(exec);try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}}while(true);}
=========main start
===================Sat Nov 15 18:24:59 CST 2014========================
exec.getPoolSize()=0
exec.getCorePoolSize()=1
exec.getLargestPoolSize()=0
exec.getMaximumPoolSize()=128
exec.getActiveCount()=0
exec.getTaskCount()=0
exec.getCompletedTaskCount()=0
===================Sat Nov 15 18:24:59 CST 2014========================
exec.getPoolSize()=10
exec.getCorePoolSize()=1
exec.getLargestPoolSize()=10
exec.getMaximumPoolSize()=128
exec.getActiveCount()=10
exec.getTaskCount()=10
exec.getCompletedTaskCount()=0
Task-3 Thread-3
Task-1 Thread-1
Task-0 Thread-0
Task-2 Thread-2
Task-6 Thread-6
Task-8 Thread-8
Task-7 Thread-7
Task-4 Thread-4
Task-9 Thread-9
Task-5 Thread-5
===================Sat Nov 15 18:25:04 CST 2014========================
exec.getPoolSize()=10
exec.getCorePoolSize()=1
exec.getLargestPoolSize()=10
exec.getMaximumPoolSize()=128
exec.getActiveCount()=0
exec.getTaskCount()=10
exec.getCompletedTaskCount()=10
===================Sat Nov 15 18:25:09 CST 2014========================
exec.getPoolSize()=10
exec.getCorePoolSize()=1
exec.getLargestPoolSize()=10
exec.getMaximumPoolSize()=128
exec.getActiveCount()=0
exec.getTaskCount()=10
exec.getCompletedTaskCount()=10
===================Sat Nov 15 18:25:14 CST 2014========================
exec.getPoolSize()=1
exec.getCorePoolSize()=1
exec.getLargestPoolSize()=10
exec.getMaximumPoolSize()=128
exec.getActiveCount()=0
exec.getTaskCount()=10
exec.getCompletedTaskCount()=10
===================Sat Nov 15 18:25:19 CST 2014========================
exec.getPoolSize()=1
exec.getCorePoolSize()=1
exec.getLargestPoolSize()=10
exec.getMaximumPoolSize()=128
exec.getActiveCount()=0
exec.getTaskCount()=10
exec.getCompletedTaskCount()=10
3. 使用ArrayBlockingQueue的线程池
public static class Task implements Callable<String> {private String id;Task(String id) {this.id = "Task-" + id;}@Overridepublic String call() throws Exception {try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(id + " " + Thread.currentThread().getName());return id;}}public static void main(String[] args) {System.out.println("=========main start");final ThreadPoolExecutor exec = new ThreadPoolExecutor(1, 128, 10000L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(3), new ThreadFactory() { @Override public Thread newThread(Runnable r) { return new Thread(r); } });ConcurrencyUtils.printThreadPoolExecutorInfo(exec);for (int i = 0; i < 10; i++) {exec.submit(new Task(String.valueOf(i)));}do {ConcurrencyUtils.printThreadPoolExecutorInfo(exec);try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}}while(true);}
=========main start
===================Sat Nov 15 18:29:56 CST 2014========================
exec.getPoolSize()=0
exec.getCorePoolSize()=1
exec.getLargestPoolSize()=0
exec.getMaximumPoolSize()=128
exec.getActiveCount()=0
exec.getTaskCount()=0
exec.getCompletedTaskCount()=0
===================Sat Nov 15 18:29:56 CST 2014========================
exec.getPoolSize()=7
exec.getCorePoolSize()=1
exec.getLargestPoolSize()=7
exec.getMaximumPoolSize()=128
exec.getActiveCount()=7
exec.getTaskCount()=10
exec.getCompletedTaskCount()=0
Task-4 Thread-1
Task-7 Thread-4
Task-8 Thread-5
Task-5 Thread-2
Task-0 Thread-0
Task-9 Thread-6
Task-6 Thread-3
Task-2 Thread-4
Task-3 Thread-5
Task-1 Thread-1
===================Sat Nov 15 18:30:01 CST 2014========================
exec.getPoolSize()=7
exec.getCorePoolSize()=1
exec.getLargestPoolSize()=7
exec.getMaximumPoolSize()=128
exec.getActiveCount()=0
exec.getTaskCount()=10
exec.getCompletedTaskCount()=10
===================Sat Nov 15 18:30:06 CST 2014========================
exec.getPoolSize()=7
exec.getCorePoolSize()=1
exec.getLargestPoolSize()=7
exec.getMaximumPoolSize()=128
exec.getActiveCount()=0
exec.getTaskCount()=10
exec.getCompletedTaskCount()=10
===================Sat Nov 15 18:30:11 CST 2014========================
exec.getPoolSize()=1
exec.getCorePoolSize()=1
exec.getLargestPoolSize()=7
exec.getMaximumPoolSize()=128
exec.getActiveCount()=0
exec.getTaskCount()=10
exec.getCompletedTaskCount()=10
===================Sat Nov 15 18:30:16 CST 2014========================
exec.getPoolSize()=1
exec.getCorePoolSize()=1
exec.getLargestPoolSize()=7
exec.getMaximumPoolSize()=128
exec.getActiveCount()=0
exec.getTaskCount()=10
exec.getCompletedTaskCount()=10
4. 使用LinkedBlockingQueue的线程池
public static class Task implements Callable<String> {private String id;Task(String id) {this.id = "Task-" + id;}@Overridepublic String call() throws Exception {try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(id + " " + Thread.currentThread().getName());return id;}}public static void main(String[] args) {System.out.println("=========main start");final ThreadPoolExecutor exec = new ThreadPoolExecutor(1, 128, 10000L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), new ThreadFactory() { @Override public Thread newThread(Runnable r) { return new Thread(r); } });ConcurrencyUtils.printThreadPoolExecutorInfo(exec);for (int i = 0; i < 10; i++) {exec.submit(new Task(String.valueOf(i)));}do {ConcurrencyUtils.printThreadPoolExecutorInfo(exec);try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}}while(true);}
=========main start
===================Sat Nov 15 18:31:31 CST 2014========================
exec.getPoolSize()=0
exec.getCorePoolSize()=1
exec.getLargestPoolSize()=0
exec.getMaximumPoolSize()=128
exec.getActiveCount()=0
exec.getTaskCount()=0
exec.getCompletedTaskCount()=0
===================Sat Nov 15 18:31:31 CST 2014========================
exec.getPoolSize()=1
exec.getCorePoolSize()=1
exec.getLargestPoolSize()=1
exec.getMaximumPoolSize()=128
exec.getActiveCount()=1
exec.getTaskCount()=10
exec.getCompletedTaskCount()=0
Task-0 Thread-0
Task-1 Thread-0
===================Sat Nov 15 18:31:36 CST 2014========================
exec.getPoolSize()=1
exec.getCorePoolSize()=1
exec.getLargestPoolSize()=1
exec.getMaximumPoolSize()=128
exec.getActiveCount()=1
exec.getTaskCount()=10
exec.getCompletedTaskCount()=2
Task-2 Thread-0
Task-3 Thread-0
Task-4 Thread-0
===================Sat Nov 15 18:31:41 CST 2014========================
exec.getPoolSize()=1
exec.getCorePoolSize()=1
exec.getLargestPoolSize()=1
exec.getMaximumPoolSize()=128
exec.getActiveCount()=1
exec.getTaskCount()=10
exec.getCompletedTaskCount()=5
Task-5 Thread-0
Task-6 Thread-0
===================Sat Nov 15 18:31:46 CST 2014========================
exec.getPoolSize()=1
exec.getCorePoolSize()=1
exec.getLargestPoolSize()=1
exec.getMaximumPoolSize()=128
exec.getActiveCount()=1
exec.getTaskCount()=10
exec.getCompletedTaskCount()=7
Task-7 Thread-0
Task-8 Thread-0
Task-9 Thread-0
===================Sat Nov 15 18:31:51 CST 2014========================
exec.getPoolSize()=1
exec.getCorePoolSize()=1
exec.getLargestPoolSize()=1
exec.getMaximumPoolSize()=128
exec.getActiveCount()=0
exec.getTaskCount()=10
exec.getCompletedTaskCount()=10
===================Sat Nov 15 18:31:56 CST 2014========================
exec.getPoolSize()=1
exec.getCorePoolSize()=1
exec.getLargestPoolSize()=1
exec.getMaximumPoolSize()=128
exec.getActiveCount()=0
exec.getTaskCount()=10
exec.getCompletedTaskCount()=10
===================Sat Nov 15 18:32:01 CST 2014========================
exec.getPoolSize()=1
exec.getCorePoolSize()=1
exec.getLargestPoolSize()=1
exec.getMaximumPoolSize()=128
exec.getActiveCount()=0
exec.getTaskCount()=10
exec.getCompletedTaskCount()=10
5 线程池工作规则(重点)
认真看了上面三个demo的执行结果,不难理解
ThreadPoolExecutor是这样一种存在当任务数小于corePoolSize时候,即便有线程空闲,也会创建新的线程,当任务数量大于等于于corePoolSize的时候就会放到队列里面,
如果无法将请求加入队列,就增加新的线程,如果线程多于corePoolSize并且空闲下来会根据keepAliveTime和unit参数在某时间 来关闭线程。
如果keepAliveTime为0则用完随即关闭(试过100个task,getLargestPoolSize()却是7,然后增加task的执行时间,getLargestPoolSize()会增大)
ThreadPoolExecutor对象是和队列形态相关的,有三种形式的队列,
1. LinkedBlockingQueue是无界队列,如果池中的线程数量少于corePoolSize则创建新的线程即便是有线程空闲。如果待处理的任务数量超过了corePoolSize则放到队列里面,因为队列无界,所以除非线程过多导致崩溃或是内存溢出,task会一直往队列里面放,不再分配新的线程。
也就是说当队列是LinkedBlockingQueue对象的时候 maximumPoolSize参数没啥用,因为线程数量不会大于corePoolSize了,构造时候会判断maximumPoolSize>=corePoolSize否则抛参数异常。
2. ArrayBlockingQueue是有界队列,如上所述,当线程数等于corePoolSize时候就把待处理的任务放入请求队列,当队列满了的时候,会增加新的线程,直到线程maximumPoolSize,如果还有任务无法处理则会回调RejectedExecutionHandler接口
3.SynchronousQueue使用直接提交策略
SynchronousQueue是无界的,也就是说他存数任务的能力是没有限制的,但是由于该Queue本身的特性,在某次添加元素后必须等待其他线程取走后才能继续添加。在这里不是核心线程便是新创建的线程
{关于阻塞队列 见《集合框架》}
对于使用SynchronousQueue的作用jdk中写的很清楚:此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。
getLargestPoolSize()表示池中同时存在线程数 的最大值,不是分配过的线程数。
getPoolSize()线程池中当前线程数。
getCorePoolSize() 就是corePoolSize的属性值(第一个参数)
getMaximumPoolSize()就是第二个参数对相应的属性值。
getActiveCount()活动的任务数
getTaskCount()总任务数
getCompletedTaskCount()完成的任务数。
验证一下SynchronousQueue特性
public static class Task implements Callable<String> {private String id;Task(String id) {this.id = "Task-" + id;}@Overridepublic String call() throws Exception {System.out.println("call start" +id + " " + Thread.currentThread().getName());try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("call end" +id + " " + Thread.currentThread().getName());return id;}}public static void main(String[] args) {System.out.println("=========main start");final ThreadPoolExecutor exec = new ThreadPoolExecutor(5, 128, 0L, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(), new ThreadFactory() { @Override public Thread newThread(Runnable r) { return new Thread(r); } });for (int i = 0; i < 10; i++) {exec.submit(new Task(String.valueOf(i)));}}
=========main start
call startTask-0 Thread-0
call startTask-2 Thread-2
call startTask-1 Thread-1
call startTask-4 Thread-4
call startTask-3 Thread-3
call startTask-6 Thread-6
call startTask-5 Thread-5
call startTask-7 Thread-7
call startTask-8 Thread-8
call startTask-9 Thread-9
call endTask-4 Thread-4
call endTask-6 Thread-6
call endTask-5 Thread-5
call endTask-3 Thread-3
call endTask-1 Thread-1
call endTask-0 Thread-0
call endTask-2 Thread-2
call endTask-8 Thread-8
call endTask-9 Thread-9
call endTask-7 Thread-7
从结果上看,虽然task2 在task1前面但是task2的thread是thread-2;task1 的是thread-1这说明task1先分配线程执行,只是输出在后面。
SynchronousQueue保证先进入队列的出队列(先被执行)
怎么理解“SynchronousQueue在某次添加元素后必须等待其他线程取走后才能继续添加”呢?一个任务加入队列就分配线程,然后再让下一个任务进入队列,以此类推,好像一个管道
- [Java并发]-04-ThreadPoolExecutor类创建线程池对象和源码分析
- Java并发包源码学习之线程池(一)ThreadPoolExecutor源码分析
- JAVA线程池(ThreadPoolExecutor)源码分析
- JAVA线程池(ThreadPoolExecutor)源码分析
- JAVA线程池(ThreadPoolExecutor)源码分析
- Java 线程池 ThreadPoolExecutor 源码分析
- JAVA线程池(ThreadPoolExecutor)源码分析
- 《Java源码分析》:线程池 ThreadPoolExecutor
- Java线程池ThreadPoolExecutor源码分析
- Java 线程池 ThreadPoolExecutor 源码分析
- java并发编程之源码分析ThreadPoolExecutor线程池实现原理
- 线程池ThreadPoolExecutor类源码分析
- Java线程池ThreadPoolExecutor使用和分析
- ThreadPoolExecutor线程池源码分析
- ThreadPoolExecutor线程池源码分析
- Java并发编程:线程池创建及源码分析
- Java并发编程:ThreadPoolExecutor类及方法源码分析
- 我之见--java 多线程 线程池ThreadPoolExecutor源码分析
- 华为介绍-应届生必看
- 图像的极坐标表示
- Delphi XE5 for Android (十)
- POJ 1163 The Triangle
- Requesting JavaScript AST from selection
- [Java并发]-04-ThreadPoolExecutor类创建线程池对象和源码分析
- Delphi XE5 for Android (十一)
- web.xml中的jsp-config元素以及taglib元素
- 5900终于成功了
- PHP常用mysql函数
- 在android studio中新建android gradle project的时候connect refused
- cf377A Maze DFS
- 使用栈结构完成四则运算
- unity3d 安卓播放视频不使用视频纹理