前言
我们可以通过 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. flask 面试题

    1,什么是Flask,有什么优点?概念解释Flask是一个Web框架,就是提供一个工具,库和技术来允许你构建一个Web应用程序.这个Web应用程序可以是一些Web页面,博客,wiki,基于Web的日里 ...

  2. 第九单元 利用vi编辑器创建和编辑正文文件

    vi编辑器简介  什么是vi vi编辑器的操作模式 vi编辑器的3种基本模式 在vi编辑器中光标的移动 移动光标位置的键与光标移动间的关系 进入插入模式 从命令行模式进入插入模式的命令 在命令行模式下 ...

  3. Dubbo常用配置文件分析及核心源码阅读(SPI.Extension)

    1.多版本支持: 基于上篇博客的 快速启动 Dubbo 服务 的代码进行多版本支持的演示:基于原来的实现类GpHelloImpl ,我们需要新增一个新版本的实类:GpHelloImpl2 public ...

  4. laravel Blade 模板引擎

    与视图文件紧密关联的就是模板代码,我们在视图文件中通过模板代码和 HTML 代码结合实现视图的渲染.和很多其他后端语言不同,PHP 本身就可以当做模板语言来使用,但是这种方式有很多缺点,比如安全上的隐 ...

  5. ural1018依赖背包-边权

    其实用点权更简单,但这种做法是边权的 /* 依赖背包问题 dp[u][k]表示u结点往下共走k步的最大值 */ #include<iostream> #include<cstring ...

  6. 用 DocumentFormat.OpenXml 和Microsoft.Office.Interop.Word 写入或者读取word文件

    using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Tex ...

  7. tensorflow:验证码的识别(中)

    三.训练识别模型 首先先拷贝一个nets文件夹,主要使用的是文件夹下的两个文件nets_factory.py.alexnet.py,用于导入训练使用的网络alexnet. nets_factory.p ...

  8. pycaffe简明文档

    pycaffe简明文档 by ChrisZZ, imzhuo@foxmail.com 2018年01月18日19:00:56 说明 caffe的python接口没有官方说明文档,例如查看一个函数的用法 ...

  9. C# float与UInt16互转

    //float拆分成两个UInt16 public static UInt16 FloatToTwoUInt16(float f) { byte[] bs = BitConvert.GetBytes( ...

  10. Oracle Client(客户端) 安装与配置

    因为工作需要,需要通过本地oracle客户端将数据导入到远程服务器上的oracle数据库中.从csdn下了很多oracle客户端,都是属于精简版,缺少imp.exe文件,造成无法导入数据.所以最终从o ...