我们知道,受限于硬件、内存和性能,我们不可能无限制的创建任意数量的线程,因为每一台机器允许的最大线程是一个有界值。也就是说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相关推荐

  1. 线程池中 corePoolSize, maximumPoolSize, poolSize理解

    2019独角兽企业重金招聘Python工程师标准>>> corePoolSize 线程池基本大小 maximumPoolSize 线程池最大数 poolSize: 当前线程数 当po ...

  2. ThreadPoolExecutor线程池核心参数详解

    理解ThreadPoolExecutor线程池的corePoolSize.maximumPoolSize和poolSize 我们知道,受限于硬件.内存和性能,我们不可能无限制的创建任意数量的线程,因为 ...

  3. Java Executor源码解析(3)—ThreadPoolExecutor线程池execute核心方法源码【一万字】

    基于JDK1.8详细介绍了ThreadPoolExecutor线程池的execute方法源码! 上一篇文章中,我们介绍了:Java Executor源码解析(2)-ThreadPoolExecutor ...

  4. 【Java 并发编程】线程池机制 ( ThreadPoolExecutor 线程池构造参数分析 | 核心线程数 | 最大线程数 | 非核心线程存活时间 | 任务阻塞队列 )

    文章目录 前言 一.ThreadPoolExecutor 构造参数 二.newCachedThreadPool 参数分析 三.newFixedThreadPool 参数分析 四.newSingleTh ...

  5. java中四种线程池及poolSize、corePoolSize、maximumPoolSize

    目录 ThreadPoolExecutor重要参数 poolSize.corePoolSize.maximumPoolSize 四种线程池 newFixedThreadPool newCachedTh ...

  6. Java自带的线程池ThreadPoolExecutor详细介绍说明和实例运用

    Java 5 开始,Java 提供了自己的线程池.线程池就是一个线程的容器,每次只执行额定数量的线程. java.util.concurrent.ThreadPoolExecutor 就是这样的线程池 ...

  7. 用10086客服热线理解Java高级多线程之线程池

    Java高级多线程之线程池 客服热线案例 引入线程池 1.线程的概念 2.线程池的作用: 获取线程池 1.常用的线程池接口和类 2.代码案例 Callable接口 1.概念简述 2.应用场景 3.方法 ...

  8. java 线程池的理解_JAVA线程池原理的理解

    线程池原理基础理解: 线程池初始化规定个数的线程,然后这些线程一直运行,并且监控线程队列,只要线程队列被添加进线程,那么线程池不断从队列中取出线程运行.直到队列中的线程为空.实例代码如下: packa ...

  9. Java并发编程:线程池

    一.为什么使用线程池 使用线程的时候直接就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降 ...

最新文章

  1. 报名 | AI Time :论道AI安全与伦理
  2. memcache 启动 储存原理 集群
  3. Win7+VS2010环境下CEGUI 0.8.4编译过程详解
  4. linux-squirrel
  5. 算法设计之—常用算法之-分支界定法
  6. 计数排序的应用----排序字符串
  7. 如何降低微服务测试成本?我的经验之谈
  8. vscode中如何让vue文件语法高亮_VS code 你们都在用吗?或许你们需要看一下(语言相关)篇...
  9. 【312天】我爱刷题系列071(2017.12.14)
  10. 天梯—输出GPLT(C语言)
  11. 使用C#和Excel进行报表开发(三)-生成统计图(Chart)
  12. 利用bat修复office文件图标
  13. php网站 怎么查是否开源,怎么查看网站的开源程序?
  14. 【编译原理】【实验】THOMPSON 算法的实现
  15. 机器学习:特征选择之RFormula(SparkMLlib中的RFormula)
  16. CSP介绍、以及使用CryptoAPI枚举CSP并获取其属性
  17. 连接到系统上的设备没有发挥作用解决方案
  18. 用python做一个文本翻译器,自动将中文翻译成英文,超方便的
  19. linux Mint桌面美化
  20. 软件测试中UT,IT,ST,UAT

热门文章

  1. C 实现高性能内存池
  2. 利用C/C++实现较完整贪吃蛇游戏
  3. redis 内存不足 排查_排查redis占用内存达90%以上
  4. iphone换机数据迁移_苹果手机换华为、小米怎么同步数据?来了!
  5. pat 乙级 1041 考试座位号(C++)
  6. 节点式光端机与点对点式光端机的区别
  7. 【渝粤教育】电大中专消费者行为学 (3)作业 题库
  8. 【无线电波】蓝牙Bluetooth来源 原理?有无辐射影响健康 是否安全!?
  9. php登陆框_PHP 登录完成跳转上一访问页面
  10. c语言选择题答案在哪查,C语言选择题及答案