java corepoolsize_理解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 booleanaddIfUnderCorePoolSize(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 booleanaddIfUnderMaximumPoolSize(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
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 queue
r =workQueue.poll();else if (poolSize > corePoolSize ||allowCoreThreadTimeOut)
r=workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);elser=workQueue.take();if (r != null)returnr;if(workerCanExit()) {if (runState >= SHUTDOWN) //Wake up others
interruptIdleWorkers();return null;
}//Else retry
} catch(InterruptedException ie) {//On interruption, re-check runState
}
}
}
(poolSize > corePoolSize || allowCoreThreadTimeOut)这个条件,就是用来判断是否允许当前线程退出。workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);就是借助阻塞队列,让空闲线程等待keepAliveTime时间之后,恢复执行。这样空闲线程会由于超时而退出。
java corepoolsize_理解ThreadPoolExecutor线程池的corePoolSize、maximumPoolSize和poolSize相关推荐
- 线程池中 corePoolSize, maximumPoolSize, poolSize理解
2019独角兽企业重金招聘Python工程师标准>>> corePoolSize 线程池基本大小 maximumPoolSize 线程池最大数 poolSize: 当前线程数 当po ...
- ThreadPoolExecutor线程池核心参数详解
理解ThreadPoolExecutor线程池的corePoolSize.maximumPoolSize和poolSize 我们知道,受限于硬件.内存和性能,我们不可能无限制的创建任意数量的线程,因为 ...
- Java Executor源码解析(3)—ThreadPoolExecutor线程池execute核心方法源码【一万字】
基于JDK1.8详细介绍了ThreadPoolExecutor线程池的execute方法源码! 上一篇文章中,我们介绍了:Java Executor源码解析(2)-ThreadPoolExecutor ...
- 【Java 并发编程】线程池机制 ( ThreadPoolExecutor 线程池构造参数分析 | 核心线程数 | 最大线程数 | 非核心线程存活时间 | 任务阻塞队列 )
文章目录 前言 一.ThreadPoolExecutor 构造参数 二.newCachedThreadPool 参数分析 三.newFixedThreadPool 参数分析 四.newSingleTh ...
- java中四种线程池及poolSize、corePoolSize、maximumPoolSize
目录 ThreadPoolExecutor重要参数 poolSize.corePoolSize.maximumPoolSize 四种线程池 newFixedThreadPool newCachedTh ...
- Java自带的线程池ThreadPoolExecutor详细介绍说明和实例运用
Java 5 开始,Java 提供了自己的线程池.线程池就是一个线程的容器,每次只执行额定数量的线程. java.util.concurrent.ThreadPoolExecutor 就是这样的线程池 ...
- 用10086客服热线理解Java高级多线程之线程池
Java高级多线程之线程池 客服热线案例 引入线程池 1.线程的概念 2.线程池的作用: 获取线程池 1.常用的线程池接口和类 2.代码案例 Callable接口 1.概念简述 2.应用场景 3.方法 ...
- java 线程池的理解_JAVA线程池原理的理解
线程池原理基础理解: 线程池初始化规定个数的线程,然后这些线程一直运行,并且监控线程队列,只要线程队列被添加进线程,那么线程池不断从队列中取出线程运行.直到队列中的线程为空.实例代码如下: packa ...
- Java并发编程:线程池
一.为什么使用线程池 使用线程的时候直接就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降 ...
最新文章
- 报名 | AI Time :论道AI安全与伦理
- memcache 启动 储存原理 集群
- Win7+VS2010环境下CEGUI 0.8.4编译过程详解
- linux-squirrel
- 算法设计之—常用算法之-分支界定法
- 计数排序的应用----排序字符串
- 如何降低微服务测试成本?我的经验之谈
- vscode中如何让vue文件语法高亮_VS code 你们都在用吗?或许你们需要看一下(语言相关)篇...
- 【312天】我爱刷题系列071(2017.12.14)
- 天梯—输出GPLT(C语言)
- 使用C#和Excel进行报表开发(三)-生成统计图(Chart)
- 利用bat修复office文件图标
- php网站 怎么查是否开源,怎么查看网站的开源程序?
- 【编译原理】【实验】THOMPSON 算法的实现
- 机器学习:特征选择之RFormula(SparkMLlib中的RFormula)
- CSP介绍、以及使用CryptoAPI枚举CSP并获取其属性
- 连接到系统上的设备没有发挥作用解决方案
- 用python做一个文本翻译器,自动将中文翻译成英文,超方便的
- linux Mint桌面美化
- 软件测试中UT,IT,ST,UAT
热门文章
- C 实现高性能内存池
- 利用C/C++实现较完整贪吃蛇游戏
- redis 内存不足 排查_排查redis占用内存达90%以上
- iphone换机数据迁移_苹果手机换华为、小米怎么同步数据?来了!
- pat 乙级 1041 考试座位号(C++)
- 节点式光端机与点对点式光端机的区别
- 【渝粤教育】电大中专消费者行为学 (3)作业 题库
- 【无线电波】蓝牙Bluetooth来源 原理?有无辐射影响健康 是否安全!?
- php登陆框_PHP 登录完成跳转上一访问页面
- c语言选择题答案在哪查,C语言选择题及答案