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 ...
随机推荐
- lr11录制脚本出现中文乱码
录制脚本前,打开录制选项配置对话框Record-Options,进入到Advanced标签,先勾选“Support charset”,然后选择中支持UTF-8.在IIS中找到Web.Config文 ...
- java或判断优化小技巧
写业务代码的时候,我们经常要做条件判断,有的时候条件判断的或判断长达20多个.reg.equals("1") || reg.equals("2") || reg ...
- 智能合约语言 Solidity 教程系列7 - 以太单位及时间单位
这是Solidity教程系列文章第7篇介绍以太单位及时间单位,系列带你全面深入理解Solidity语言. 写在前面 Solidity 是以太坊智能合约编程语言,阅读本文前,你应该对以太坊.智能合约有所 ...
- mongodb的安装和配置
1.下载安装 wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.0.6.tgz tar zxf mongodb-linux-x8 ...
- 小程序实现非swiper组件的自定义伪3D轮播图
效果如下: 我用了很笨的方法实现的,大致就是: 1.当前点击的div(view)如果前后都有内容,那么,当前div(view)就设置到中间,前一个就设置到左边,前一个的前面所有全部设置到最左边,后面一 ...
- Oracle中死锁与等待
在数据库中有两种基本的锁类型:排它锁(Exclusive Locks,即X锁)和共享锁(即S锁).当数据对象被加上排它锁时,其他的事务不能不 能对它读取和修改.加了共享锁的数据对象可以被其他事务读取 ...
- 实现win的on程序数据更新
枚举是一组描述性的名称定义一组有限的值,不包含方法对可能的值进行约束枚举是一组指定的常数,对可能的值进行约束枚举使用时直观方便.更易于维护 pictureBox控件属性名称 说明image ...
- python全栈学习--day9(函数初始)
Python 函数 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.你已经知道Python提供了许多内建函数,比如print().但你也 ...
- 网络1712--c语言字符数组作业总结..
---恢复内容开始--- 作业亮点 1.总体情况 1.大部分同学利用了流程图后,对于思路的理解有了提升. 2.很多同学在总结方面写的很不错,能够罗列问题贴出解决问题,我们能够看到你们的进步 2.作业发 ...
- 201621123050 《Java程序设计》第7周学习总结
1. 本周学习总结 1.1 思维导图:Java图形界面总结 2.书面作业 1. GUI中的事件处理 1.1 写出事件处理模型中最重要的几个关键词. 1.事件:用户的操作,例如点击或输入之类的操作 2. ...