ThreadPoolExecutor线程池核心参数详解
理解ThreadPoolExecutor线程池的corePoolSize、maximumPoolSize和poolSize
我们知道,受限于硬件、内存和性能,我们不可能无限制的创建任意数量的线程,因为每一台机器允许的最大线程是一个有界值。也就是说ThreadPoolExecutor管理的线程数量是有界的。线程池就是用这些有限个数的线程,去执行提交的任务。然而对于多用户、高并发的应用来说,提交的任务数量非常巨大,一定会比允许的最大线程数多很多。为了解决这个问题,必须要引入排队机制,或者是在内存中,或者是在硬盘等容量很大的存储介质中。J.U.C提供的ThreadPoolExecutor只支持任务在内存中排队,通过BlockingQueue暂存还没有来得及执行的任务。
任务的管理是一件比较容易的事,复杂的是线程的管理,这会涉及线程数量、等待/唤醒、同步/锁、线程创建和死亡等问题。ThreadPoolExecutor与线程相关的几个成员变量是:keepAliveTime、allowCoreThreadTimeOut、poolSize、corePoolSize、maximumPoolSize,它们共同负责线程的创建和销毁。
corePoolSize:
线程池的基本大小,即在没有任务需要执行的时候线程池的大小,并且只有在工作队列满了的情况下才会创建超出这个数量的线程。这里需要注意的是:在刚刚创建ThreadPoolExecutor的时候,线程并不会立即启动,而是要等到有任务提交时才会启动,除非调用了prestartCoreThread/prestartAllCoreThreads事先启动核心线程。再考虑到keepAliveTime和allowCoreThreadTimeOut超时参数的影响,所以没有任务需要执行的时候,线程池的大小不一定是corePoolSize。
maximumPoolSize:
线程池中允许的最大线程数,线程池中的当前线程数目不会超过该值。如果队列中任务已满,并且当前线程个数小于maximumPoolSize,那么会创建新的线程来执行任务。这里值得一提的是largestPoolSize,该变量记录了线程池在整个生命周期中曾经出现的最大线程个数。为什么说是曾经呢?因为线程池创建之后,可以调用setMaximumPoolSize()改变运行的最大线程的数目。
poolSize:
线程池中当前线程的数量,当该值为0的时候,意味着没有任何线程,线程池会终止;同一时刻,poolSize不会超过maximumPoolSize。
现在我们通过ThreadPoolExecutor.execute()方法,看一下这3个属性的关系,以及线程池如何处理新提交的任务。以下源码基于JDK1.6.0_37版本。
private boolean addIfUnderCorePoolSize(Runnable firstTask) {Thread t = null;final ReentrantLock mainLock = this.mainLock;mainLock.lock();try {if (poolSize < corePoolSize && runState == RUNNING)t = addThread(firstTask);} finally {mainLock.unlock();}if (t == null)return false;t.start();return true;}private boolean addIfUnderMaximumPoolSize(Runnable firstTask) {Thread t = null;final ReentrantLock mainLock = this.mainLock;mainLock.lock();try {if (poolSize < maximumPoolSize && runState == RUNNING)t = addThread(firstTask);} finally {mainLock.unlock();}if (t == null)return false;t.start();return true;}
新提交一个任务时的处理流程很明显:
1、如果当前线程池的线程数还没有达到基本大小(poolSize < corePoolSize),无论是否有空闲的线程新增一个线程处理新提交的任务;
2、如果当前线程池的线程数大于或等于基本大小(poolSize >= corePoolSize) 且任务队列未满时,就将新提交的任务提交到阻塞队列排队,等候处理workQueue.offer(command);
3、如果当前线程池的线程数大于或等于基本大小(poolSize >= corePoolSize) 且任务队列满时;
3.1、当前poolSize<maximumPoolSize,那么就新增线程来处理任务;
3.2、当前poolSize=maximumPoolSize,那么意味着线程池的处理能力已经达到了极限,此时需要拒绝新增加的任务。至于如何拒绝处理新增的任务,取决于线程池的饱和策略RejectedExecutionHandler。
Queuing
Any BlockingQueue may be used to transfer and hold submitted tasks. The use of this queue interacts with pool sizing:
- If fewer than corePoolSize threads are running, the Executor always prefers adding a new thread rather than queuing.
- If corePoolSize or more threads are running, the Executor always prefers queuing a request rather than adding a new thread.
- If a request cannot be queued, a new thread is created unless this would exceed maximumPoolSize, in which case, the task will be rejected.
1、corePoolSize:核心线程数* 核心线程会一直存活,及时没有任务需要执行* 当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建新线程处理* 设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭2、queueCapacity:任务队列容量(阻塞队列)* 当核心线程数达到最大时,新任务会放在队列中排队等待执行3、maxPoolSize:最大线程数* 当线程数>=corePoolSize,且任务队列已满时。线程池会创建新线程来处理任务* 当线程数=maxPoolSize,且任务队列已满时,线程池会拒绝处理任务而抛出异常4、 keepAliveTime:线程空闲时间* 当线程空闲时间达到keepAliveTime时,线程会退出,直到线程数量=corePoolSize* 如果allowCoreThreadTimeout=true,则会直到线程数量=05、allowCoreThreadTimeout:允许核心线程超时6、rejectedExecutionHandler:任务拒绝处理器* 两种情况会拒绝处理任务:- 当线程数已经达到maxPoolSize,切队列已满,会拒绝新任务- 当线程池被调用shutdown()后,会等待线程池里的任务执行完毕,再shutdown。如果在调用shutdown()和线程池真正shutdown之间提交任务,会拒绝新任务* 线程池会调用rejectedExecutionHandler来处理这个任务。如果没有设置默认是AbortPolicy,会抛出异常* ThreadPoolExecutor类有几个内部实现类来处理这类情况:- AbortPolicy 丢弃任务,抛运行时异常- CallerRunsPolicy 执行任务- DiscardPolicy 忽视,什么都不会发生- DiscardOldestPolicy 从队列中踢出最先进入队列(最后一个执行)的任务* 实现RejectedExecutionHandler接口,可自定义处理器
接下来我们看下allowCoreThreadTimeOut和keepAliveTime属性的含义。
在压力很大的情况下,线程池中的所有线程都在处理新提交的任务或者是在排队的任务,这个时候线程池处在忙碌状态。如果压力很小,那么可能很多线程池都处在空闲状态,这个时候为了节省系统资源,回收这些没有用的空闲线程,就必须提供一些超时机制,这也是线程池大小调节策略的一部分。通过corePoolSize和maximumPoolSize,控制如何新增线程;通过allowCoreThreadTimeOut和keepAliveTime,控制如何销毁线程。
allowCoreThreadTimeOut:
该属性用来控制是否允许核心线程超时退出。默认值为:false。If false,core threads stay alive even when idle.If true, core threads use keepAliveTime to time out waiting for work。如果线程池的大小已经达到了corePoolSize,不管有没有任务需要执行,线程池都会保证这些核心线程处于存活状态。可以知道:该属性只是用来控制核心线程的。
keepAliveTime:
如果一个线程处在空闲状态的时间超过了该属性值,就会因为超时而退出。举个例子,如果线程池的核心大小corePoolSize=5,而当前大小poolSize =8,那么超出核心大小的线程,会按照keepAliveTime的值判断是否会超时退出。如果线程池的核心大小corePoolSize=5,而当前大小poolSize =5,那么线程池中所有线程都是核心线程,这个时候线程是否会退出,取决于allowCoreThreadTimeOut。
Runnable getTask() {for (;;) {try {int state = runState;if (state > SHUTDOWN)return null;Runnable r;if (state == SHUTDOWN) // Help drain queuer = workQueue.poll();else if (poolSize > corePoolSize || allowCoreThreadTimeOut)r = workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);elser = workQueue.take();if (r != null)return r;if (workerCanExit()) {if (runState >= SHUTDOWN) // Wake up othersinterruptIdleWorkers();return null;}// Else retry} catch (InterruptedException ie) {// On interruption, re-check runState}}}
(poolSize > corePoolSize || allowCoreThreadTimeOut)这个条件,就是用来判断是否允许当前线程退出。workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);就是借助阻塞队列,让空闲线程等待keepAliveTime时间之后,恢复执行。这样空闲线程会由于超时而退出。
ThreadPoolExecutor线程池核心参数详解相关推荐
- Java线程池七大参数详解和配置
目录 一.corePoolSize核心线程数 二.maximunPoolSize最大线程数 三.keepAliveTime空闲线程存活时间 四.unit空闲线程存活时间的单位 五.workQueue线 ...
- 并发编程五:java并发线程池底层原理详解和源码分析
文章目录 java并发线程池底层原理详解和源码分析 线程和线程池性能对比 Executors创建的三种线程池分析 自定义线程池分析 线程池源码分析 继承关系 ThreadPoolExecutor源码分 ...
- 线程池invokeAll方法详解
线程池invokeAll方法详解 问题起源与抽象 问题排查与猜测 猜测一:invokeAll 在异步执行后会不会同步等待线程执行完毕获取最终结果 猜测二:队列里面可能存在第一次调用 invokeAll ...
- pthread_create函数的详细讲解(包括向线程函数传递参数详解)
pthread_create是UNIX环境创建线程函数 头文件 #include<pthread.h> 函数声明 int pthread_create(pthread_t*restrict ...
- 线程与线程池(一条龙详解)
一:前言 一个问题引出的学习笔记 并发类库提供的线程池实现有哪些? 其实Executors已经为我们封装好了 4 种常见的功能线程池,如下: 定长线程池(FixedThreadPool) 定时线程池( ...
- 第9课:jvm的gc时候核心参数详解:-XX:NewRatio、-XX:SurvivorRatio、-XX:NewSize、-XX:MaxNewSize
内容: 1.-XX:NewRatio 2.-XX:SurvivorRatio 3.-XX:NewSize和-XX:MaxNewSize 一.JVM内存结构图 二.参数详解 1.-xx: ...
- 【Java 并发编程】线程池机制 ( ThreadPoolExecutor 线程池构造参数分析 | 核心线程数 | 最大线程数 | 非核心线程存活时间 | 任务阻塞队列 )
文章目录 前言 一.ThreadPoolExecutor 构造参数 二.newCachedThreadPool 参数分析 三.newFixedThreadPool 参数分析 四.newSingleTh ...
- 【多线程】线程池拒绝策略详解与自定义拒绝策略
线程池的拒绝策略 ThreadPoolExecutor内部有实现4个拒绝策略,默认为AbortPolicy策略 CallerRunsPolicy:由调用execute方法提交任务的线程来执行这个任务 ...
- ThreadPoolExecutor线程池及参数介绍
线程池类图如下: 使用Executors工具类创建的线程池,都是创建的ThreadPoolExecutor对象.这个对象的核心参数有7个: 1.corePoolSize 核心线程数,即便线程空闲也会一 ...
最新文章
- 最新Spring整合MyBatis详解教程
- 解决phpQuery(DOMDocument)解析部分HTML会产生乱码的问题
- python设置ini文件中的值_PyCharm设置python文件模板,自动读取文件信息。
- 《Android 应用测试指南》——第2章,第2.4节包浏览器
- 关于BEA-000402和BEA-000438(没有进程来读取写入管道的数据)
- dialog窗口编程的入门使用
- WPS2012交叉引用技巧,word比wps这点强更新參考文献
- LintCode Python 简单级题目 112.删除链表中的重复元素
- 2ask信号调制与解调 matlab,2ASK2ASK调制与解调系统的MATLAB实现及性能分析
- js获取当前URL中的参数
- 集合的相关概念(开闭、有界无界、内点边界点等)
- windows快速创建文本文档的几个方法快捷键和
- 2019年最新手机CPU处理器性能排行天梯图
- java 合并mp3
- 水平线标记的用法和属性
- 织梦留言板模板 .php,DEDECMS 留言薄模块的使用方法
- matlab 双y轴 三y轴
- 'config.h' file not found 的解决方法以及可能遇到的问题
- 布局布线流程的10大步骤
- mysql ddl之增加字段