前言
我们可以通过 java.util.concurrent.ThreadPoolExecutor 来创建一个线程池:
new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, milliseconds, runnableTaskQueue, threadFactory, handler);
参数说明:
1、corePoolSize(线程池的基本大小):当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建。如果调用了线程池的prestartAllCoreThreads方法,线程池会提前创建并启动所有基本线程。
2、maximumPoolSize(线程池最大数量):线程池允许创建的最大线程数。如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。值得注意的是,如果使用了无界的任务队列这个参数就没用了。
3、keepAliveTime(线程活动时间):线程池的工作线程空闲后,保持存活的时间。所以如果任务很多,并且每个任务执行的时间比较短,可以调大时间,提高线程利用率。
4、TimeUnit(线程活动时间的单位):可选的单位有天(Days)、小时(HOURS)、分钟(MINUTES)、毫秒(MILLISECONDS)、微秒(MICROSECONDS,千分之一毫秒)和纳秒(NANOSECONDS,千分之一微秒)
5、runnableTaskQueue(任务队列):用于保存等待执行的任务的阻塞队列。 可以选择以下几个阻塞队列:
(1)ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,FIFO(先进先出)。
(2)LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue,静态工厂方法Executors.newFixedThreadPool()使用了这个队列。
(3)SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool()使用了这个队列。
(4)PriorityBlockingQueue:一个具有优先级的无限阻塞队列。
6、threadFactory:用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字。
7、RejectedExecutionHandler (饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略还处理新提交的任务。它可以有如下四个选项:
AbortPolicy:直接抛出异常,默认情况下采用这种策略
CallerRunsPolicy:只用调用者所在线程来运行任务
DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务
DiscardPolicy:不处理,丢弃掉

按照一般的理解,初始化线程池,只需要一个 maximumPoolSize 入参就行了,corePoolSize 和 maximumPoolSize 似乎有重复的嫌疑(一开始我也是这么以为的),其实不是这样的,下面我们来详细说说这两者的区别和联系。

要理解 这两个参数的区别,首先要知道,关于 ThreadPoolExecutor 相关的任务线程,它包含两部分:(1)正在线程池中运行的任务线程、(2)在taskQueue 中排队等待运行的任务线程。

1、当线程池初始化完成之后,executorService.submit(new Thread(...)); 加入需要运行的任务线程,因为线程池初始化是没有线程运行的,所以当提交一个任务到线程池时,线程池会创建一个线程来直接执行任务;
2、当线程池中正在运行的线程达到 corePoolSize 个时,线程会放到 taskQueue 中排队等候;
3、当 taskQueue(阻塞队列)的容量达到上限(即队列中不能再加入任务线程了),而当前的poolSize(就是正在线程池中运行的任务线程个数)小于 maximumPoolSize 时,则新增线程来处理任务;
4、当 taskQueue 的容量达到上限,且 poolSize = maximumPoolSize,那么线程池已经达到极限,会根据饱和策略RejectedExecutionHandler拒绝新的任务。

这个过程,像极了小朋友做客的场景:

小朋友做客,桌上放了一桌的土豆条,小朋友有一个碗(任务队列 taskQueue),碗里可以放10根土豆条(taskQueue容量 = 10),正常情况下,小朋友每次可以吃2根土豆条(嘴巴就是线程池,corePoolSize = 2),小朋友狼吞虎咽的吃每次可以吃4根土豆条(maximumPoolSize = 4)。
坐在餐桌边后,小朋友开始吃土豆,先往嘴里放了2根土豆条,但怕其他小朋友和自己抢,然后赶紧往自己的碗里加土豆条(加入队列),直到碗满了(现在小朋友嘴里2个土豆条,碗里10个土豆条)。小朋友依然害怕因为自己动作慢比其他人少吃,但是碗已经满了,所以小朋友开始狼吞虎咽地吃(嘴里同时塞4个土豆条,碗里10个土豆条)。此时小朋友已经达到极限了,虽然桌上还有土豆条,但是也只能先拒绝了(饱和策略RejectedExecutionHandler),等嘴巴里的土豆条吃完之后,再去取。

补充:

如果 使用 LinkedBlockingQueue(使用无入参构造) 对象作为 taskQueue,则不容易出现队列满情况,而容易出现内存溢出情况。

ThreadPoolExecutor 入参 corePoolSize 和 maximumPoolSize 的联系的更多相关文章

  1. ThreadPoolExecutor的corePoolSize和maximumPoolSize

    按照JDK文档的描述, 如果池中的实际线程数小于corePoolSize,无论是否其中有空闲的线程,都会给新的任务产生新的线程 如果池中的线程数>corePoolSize and <max ...

  2. 理解ThreadPoolExecutor线程池的corePoolSize、maximumPoolSize和poolSize

    我们知道,受限于硬件.内存和性能,我们不可能无限制的创建任意数量的线程,因为每一台机器允许的最大线程是一个有界值.也就是说ThreadPoolExecutor管理的线程数量是有界的.线程池就是用这些有 ...

  3. 线程池的corePoolSize、maximumPoolSize和poolSize

    什么是线程池: 为了避免系统频繁的创建和销毁线程,我们可以将创建的线程进行复用.在线程池中总有那么几个活跃的线程,也有一定的最大值限制,一个业务使用完线程之后,不是立即销毁而是将其放入到线程池中,从而 ...

  4. js的replace函数入参为function时的疑问

    近期在写js导出excel文件时运用到replace方法,此处详细的记录下它各个参数所代表的的意义. 定义和用法 replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式 ...

  5. springMVC中 request请求数据绑定到Controller入参 过程剖析

    前言:Controller方法的参数类型可以是基本类型,也可以是封装后的普通Java类型.若这个普通Java类型没有声明任何注解,则意味着它的每一个属性都需要到Request中去查找对应的请求参数.众 ...

  6. XmlRpc.net 入参结构体嵌套的转义操作

    项目使用C#开发,需要使用XmlRpc和Linux服务器端交互,用的是XmlRpc.net. 普通的程序调用入参和出差都没有问题,今天遇到入参结构体嵌套,结果 args 入参在服务器端不能解析.抓包数 ...

  7. 解决WebApi入参时多对象的问题

    我们的项目是用WebApi提供数据服务,且WebPage跟APP中都有调用到. WebApi提供的接口一多,就发现一个问题,我们项目中有很多接口是接收POST(安全原因,我们采用的是https)请求的 ...

  8. URL类型入参串调用接口

    最近通过调用另一个合作公司提供的接口实现方法,借鉴同事之前编写的方法 Models.JSON.Patient类中有各种属性,也可增加属性来满足新需求 public string TakeAppoint ...

  9. C#构造函数在继承时必须要求与父类型构造函数入参相同怎么办?

    摘要 我们都知道,C#中,在类型继承时,由于构造子类必须先构造其父类型的内容,因此,必须子类型的构造函数中调用父类型的构造函数(无参数的不需要显式声明). 但是往往我们会出现,子类型本身的构造函数大于 ...

随机推荐

  1. Confluence 6 在初始化配置时候的问题

    提交一个 服务器请求(support request) 然后在你的服务请求中同时提供下面的信息. 下载一个 LDAP 浏览器,你可以通过这个确定你的 LDAP 服务器配置正确.Atlassian 推荐 ...

  2. Android源码分析二 硬件抽象层(HAL)

    一 什么是HAL HAL 可定义一个标准接口以供硬件供应商实现,这可让 Android 忽略较低级别的驱动程序实现.借助 HAL,您可以顺利实现相关功能,而不会影响或更改更高级别的系统.HAL 实现会 ...

  3. 浅谈FastJson的TypeReference用法

    简单描述:看同事提交的代码,发现有一行代码 似曾相识,但却朦朦胧胧,ε=(´ο`*)))唉很明显自己没掌握呗,于是乎,就百度了一下 干货:对进行泛型的反序列化,使用TypeReference可以明确的 ...

  4. log4j2的log输出到tomcat/logs目录下及使用(转)

    原文链接:http://blog.csdn.net/honghailiang888/article/details/50370252 原文作者:  Herman-Hong 一.环境配置 log4j2. ...

  5. jQuery 选择器demo练习

    <!DOCTYPE html><html lang="en"><head> <meta charset="utf-8" ...

  6. C++ Primer 笔记——异常处理

    1.栈展开过程沿着嵌套函数的调用链不断查找,直到找到了与异常匹配的catch句子为止,或者也可能一直没找到匹配的catch,则程序将调用terminate,退出主函数后查找过程终止.假设找到了一个ca ...

  7. Linux系统下目录的权限意义

    访问者及其基本权限 Linux系统内的文件访问者有三种身份,分别是: a) 文件和文件目录的所有者: u---User(所有权);b) 文件和文件目录的所有者所在的组的用户: g---Group;c) ...

  8. Python语音识别(计算器)

    第一步关于导入模块的事,我试了好几个方法才发现在好像win7系统没有语音识别功能,我用了win10的又需要重新下载一个包 这样子,win32com.client模块就可以使用了 import win3 ...

  9. MySQL:日期函数、时间函数总结

    MySQL 获得当前日期时间 函数 查询昨天,时间拼接 select concat(DATE_FORMAT(date_add(now(), interval -1 day),'%Y-%d-%d'),& ...

  10. thinkphp5.0和thinkphp3.2的区别不同之处

    先看目录结构: thinkphp 5.0的目录结构, 文档:https://www.kancloud.cn/manual/thinkphp5/118008 project 应用部署目录 ├─appli ...