java线程池01-ThreadPoolExecutor构造方法参数的使用规则
为了更好的使用多线程,JDK提供了线程池供开发人员使用,目的在于减少线程的创建和销毁次数,以此达到线程的重复利用。
其中ThreadPoolExecutor是线程池中最核心的一个类,我们先简单看一下这个类的继承关系。

其中Executor是线程池的顶级接口,接口中只定义了一个方法 void execute(Runnable command);线程池的操作方法都是定义子在ExecutorService子接口中的,所以说ExecutorService是线程池真正的接口。
ThreadPoolExecutor提供了四个构造方法,我们看一下参数最全的一个构造函数;
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) { }
函数的参数含义如下:
- corePoolSize: 线程池核心线程数
- maximumPoolSize:线程池最大数
- keepAliveTime: 空闲线程存活时间
- unit: 时间单位
- workQueue: 线程池所使用的缓冲队列
- threadFactory:线程池创建线程使用的工厂
- handler: 线程池对拒绝任务的处理策略
本节我们主要对前五个参数中的corePoolSize,maximumPoolSize及workQueue是如何配合使用做出说明(keepAliveTime,unit主要对空闲线程的存活时间做的定义,见名知意,不再做出说明),以此来引出线程池的一些特性。
threadFactory和handler这两个参数都有默认值,对于它们的用法将放到其它章节去做说明。
特性一:当池中正在运行的线程数(包括空闲线程)小于corePoolSize时,新建线程执行任务。
下面用实验来说明,代码如下:
public class TestThreadPoolExecutor {
public static void main(String[] args) {
ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 3, 60L, TimeUnit.SECONDS,new LinkedBlockingQueue<>(1));
//任务1
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println("-------------helloworld_001---------------" + Thread.currentThread().getName());
}
});
try {
//主线程睡2秒
Thread.sleep(2*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//任务2
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println("-------------helloworld_002---------------" + Thread.currentThread().getName());
}
});
}
}
实验结果如下:

实验结果分析:
从实验结果上可以看出,当执行任务1的线程(thread-1)执行完成之后,任务2并没有去复用thread-1而是新建线程(thread-2)去执行任务。
特性二:当池中正在运行的线程数大于等于corePoolSize时,新插入的任务进入workQueue排队(如果workQueue长度允许),等待空闲线程来执行。
下面用实验来说明,代码如下:
public class TestThreadPoolExecutor {
public static void main(String[] args) {
ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 3, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1));
// 任务1
pool.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3 * 1000);
System.out.println("-------------helloworld_001---------------" + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// 任务2
pool.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5 * 1000);
System.out.println("-------------helloworld_002---------------" + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// 任务3
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println("-------------helloworld_003---------------" + Thread.currentThread().getName());
}
});
}
}
实验结果如下:

实验结果分析:
从实验结果上看,任务3会等待任务1执行完之后,有了空闲线程,才会执行。并没有新建线程执行任务3,这时maximumPoolSize=3这个参数不起作用。
特性三:当队列里的任务数达到上限,并且池中正在运行的线程数小于maximumPoolSize,对于新加入的任务,新建线程。
下面用实验来说明,代码如下:
public class TestThreadPoolExecutor {
public static void main(String[] args) {
ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 3, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1));
// 任务1
pool.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3 * 1000);
System.out.println("-------------helloworld_001---------------" + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// 任务2
pool.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5 * 1000);
System.out.println("-------------helloworld_002---------------" + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// 任务3
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println("-------------helloworld_003---------------" + Thread.currentThread().getName());
}
});
// 任务4
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println("-------------helloworld_004---------------" + Thread.currentThread().getName());
}
});
}
}
实验结果如下:

实验结果分析:
当任务4进入队列时发现队列的长度已经到了上限,所以无法进入队列排队,而此时正在运行的线程数(2)小于maximumPoolSize所以新建线程执行该任务。
特性四:当队列里的任务数达到上限,并且池中正在运行的线程数等于maximumPoolSize,对于新加入的任务,执行拒绝策略(线程池默认的拒绝策略是抛异常)。
下面用实验来说明,代码如下:
public class TestThreadPoolExecutor {
public static void main(String[] args) {
ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 3, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1));
// 任务1
pool.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3 * 1000);
System.out.println("-------------helloworld_001---------------" + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// 任务2
pool.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5 * 1000);
System.out.println("-------------helloworld_002---------------" + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// 任务3
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println("-------------helloworld_003---------------" + Thread.currentThread().getName());
}
});
// 任务4
pool.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("-------------helloworld_004---------------" + Thread.currentThread().getName());
}
});
// 任务5
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println("-------------helloworld_005---------------" + Thread.currentThread().getName());
}
});
}
}
实验结果如下:

实验结果分析:
当任务5加入时,队列达到上限,池内运行的线程数达到最大,故执行默认的拒绝策略,抛异常。
本文中使用到的队列类型虽然仅限于LinkedBlockingQueue这一种队列类型,但总结出来的特性,对与常用ArrayBlockingQueue 和 SynchronousQueue同样适用,些许不同及三种队列的区别,将在下个章节中说明。
最后说一点,我们作为程序员,研究问题还是要仔细深入一点的。当你对原理了解的有够透彻,开发起来也就得心应手了,很多开发中的问题和疑惑也就迎刃而解了,而且在面对其他问题的时候也可做到触类旁通。当然在开发中没有太多的时间让你去研究原理,开发中要以实现功能为前提,可等项目上线的后,你有大把的时间或者空余的时间,你大可去刨根问底,深入的去研究一项技术,为觉得这对一名程序员的成长是很重要的事情。
java线程池01-ThreadPoolExecutor构造方法参数的使用规则的更多相关文章
- Java线程池使用和常用参数
多线程问题: 1.java中为什么要使用多线程使用多线程,可以把一些大任务分解成多个小任务来执行,多个小任务之间互不影像,同时进行,这样,充分利用了cpu资源. 2.java中简单的实现多线程的方式 ...
- Java并发编程:Java线程池核心ThreadPoolExecutor的使用和原理分析
目录 引出线程池 Executor框架 ThreadPoolExecutor详解 构造函数 重要的变量 线程池执行流程 任务队列workQueue 任务拒绝策略 线程池的关闭 ThreadPoolEx ...
- 【Java 多线程】Java线程池类ThreadPoolExecutor、ScheduledThreadPoolExecutor及Executors工厂类
Java中的线程池类有两个,分别是:ThreadPoolExecutor和ScheduledThreadPoolExecutor,这两个类都继承自ExecutorService.利用这两个类,可以创建 ...
- 深入理解Java线程池:ThreadPoolExecutor
线程池介绍 在web开发中,服务器需要接受并处理请求,所以会为一个请求来分配一个线程来进行处理.如果每次请求都新创建一个线程的话实现起来非常简便,但是存在一个问题: 如果并发的请求数量非常多,但每个线 ...
- Java线程池定制ThreadPoolExecutor官方定制实例
1.仍然先看构造方法:ThreadPoolExecutor构造方法 public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,lon ...
- 学习java 线程池-1: ThreadPoolExecutor
1. Executor 该接口内只有一个接口方法 :该方法的目的就是执行指定的 Runnable (但会不会执行,或者会不会立马执行,则不一定.因为要取决于整个线程池的状态) Executor 中文的 ...
- Java线程池之ThreadPoolExecutor
前言 线程池可以提高程序的并发性能(当然是合适的情况下),因为对于没有线程的情况下,我们每一次提交任务都新建一个线程,这种方法存在不少缺陷: 1. 线程的创建和销毁的开销非常高,线程的创建需要时间, ...
- Java线程池使用和常用参数(待续)
线程池怎么实现的,核心参数讲一讲? Executors是线程池的工厂类,通过调用它的静态方法如下: Executors.newCachedThreadPool(); Executors.newFixe ...
- 关于线程池(ThreadPoolExecutor)参数的浅析
引子 线程池在项目中很常用,需要多个任务异步执行的地方我们都会去创建一个线程池. 我们看到 ThreadPoolExecutor源码中提供了更方便的工厂方法(Executors)使用. 提供方便应该是 ...
- 深入理解Java线程池:ScheduledThreadPoolExecutor
介绍 自JDK1.5开始,JDK提供了ScheduledThreadPoolExecutor类来支持周期性任务的调度.在这之前的实现需要依靠Timer和TimerTask或者其它第三方工具来完成.但T ...
随机推荐
- NYOJ街区最短路径问题
描述 一个街区有很多住户,街区的街道只能为东西.南北两种方向. 住户只可以沿着街道行走. 各个街道之间的间隔相等. 用(x,y)来表示住户坐在的街区. 例如(4,20),表示用户在东西方向第4个街道, ...
- pycharm+selenium搭建环境之no module named 'selenium'异常解决
在pycharm上搭建python+selenium自动化测试环境时,遇到一个很坑的问题:no moduel named 'selenium' 如下图: 解决方法: 1.查看你的python是否正确安 ...
- Android开发——Fragment的简单使用总结
前言: 之前搞项目的时候,就使用了这个Fragment,中间遇到了许多坑,把坑都解决了,现在写一篇较为简单的Fragment使用总结 Fragment的简单介绍: 简单来说,Fragment其实可以理 ...
- 【iOS】Core Bluetooth
本文介绍蓝牙4.0的一些基本知识. 基本概念.服务器.客户端 蓝牙LE是一个基于点对点的通信系统,其中一台设备作为服务器,另一台设备作为客户端.拥有数据的设备作为服务器,消费数据的设备作为客户端. 比 ...
- java基础学习系列三
产生随机数 例如 [a,b] Math.random*(b-a+1)+a 公式推算 [3,55]-----[0,52]+3 *53+3
- 打印机驱动冲突和端口异常:win10更新部分补丁后,打印机本地连接(连接打印机的主机)可以打印,其他共享网络中的电脑可以连接到打印机,但不能打印——解决方案
一.问题描述: 1.A(WIN10系统)表示连接打印机的电脑,P表示打印机(型号:惠普127M),B(WIN7系统)表示局域网中的电脑 2.A升级后部分补丁后,A可以使用打印机P打印文件,B显示可以连 ...
- 配置VIP地址
10.10.10.7 mysql主 redis从 10.10.10.8 mysql从 redis主 现游戏架构如上,游戏后端数据库配置集群.场景描述:若是一台服务器宕机之后,及时切换数据库保持业务 ...
- centos7 用工具nmtui更改网卡设置
1.[root@cjh-db ~ 15:13:59]#nmtui
- Android游戏开发之旅 View类详解
Android游戏开发之旅 View类详解 自定义 View的常用方法: onFinishInflate() 当View中所有的子控件 均被映射成xml后触发 onMeasure(int, int) ...
- Jquery瀑布流布局,jQuery Wookmark Load 示例
瀑布流布局非常适合大量图片的展示,一改过去裁剪图片尺寸同意的排版,每张图片都能完全展示,并错落有致,让人眼前一亮. 注意事项:img元素的width和weight属性需要写,否则定位会不准确. 查看j ...