线程池ThreadPoolExecutor参数分析
概述
比如去火车站买票, 有7个(maximumPoolSize)售票窗口, 但只有3个(corePoolSize)窗口对外开放。那么对外开放的3个窗口称为核心线程数, 而最大线程数是7个窗口。
如果3个窗口都被占用, 那么后来的人就必须在售票厅(SynchronousQueue、LinkedBlockingQueue或者ArrayBlockingQueue)排队。
但后来售票厅人越来越多, 已经人满为患, 就类似于线程队列已满。这时候火车站站长下令, 把剩下的4个窗口也打开, 也就是目前已经有7个窗口同时运行。
后来又来了一批人,7个窗口也处理不过来了, 而且售票厅人已经满了, 这时候站长就下令封锁入口,不允许其他人再进来, 这就是线程拒绝策略。
线程存活时间指的是, 允许售票员休息的最长时间, 以此限制售票员偷懒的行为。
售票厅-SynchronousQueue
public static void main(String[] args) {
// 核心线程数
int corePoolSize = 3;
//最大线程数
int maximumPoolSize = 7;
// 非核心线程的最大空闲时间
long keepAliveTime = 10L;
// 队列种类
SynchronousQueue synchronousQueue = new SynchronousQueue<Runnable>();
//LinkedBlockingQueue linkedBlockingQueue = new LinkedBlockingQueue<Runnable>();
//ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<Runnable>(5);
ThreadPoolExecutor threadpool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, synchronousQueue);
for (int i = 0; i < 20; i++) {
threadpool.execute(() -> {
System.out.println("线程名称:" + Thread.currentThread().getName());
try {
Thread.sleep(50000L);
} catch (Exception ex) {
ex.printStackTrace();
}
});
System.out.println("当前线程数量:" + threadpool.getPoolSize());
System.out.println("当前队列大小:" + synchronousQueue.size());
}
}
输出结果
当前线程数量:1
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task org.tonny.threads.threadpool.ThreadPool$$Lambda$1/20132171@cc34f4d rejected from java.util.concurrent.ThreadPoolExecutor@17a7cec2[Running, pool size = 7, active threads = 7, queued tasks = 0, completed tasks = 0]
当前队列大小:0
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
线程名称:pool-1-thread-1
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
当前线程数量:2
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
当前队列大小:0
at org.tonny.threads.threadpool.ThreadPool.main(ThreadPool.java:19)
线程名称:pool-1-thread-2
当前线程数量:3
当前队列大小:0
线程名称:pool-1-thread-3
当前线程数量:4
当前队列大小:0
当前线程数量:5
当前队列大小:0
线程名称:pool-1-thread-4
当前线程数量:6
当前队列大小:0
当前线程数量:7
当前队列大小:0
线程名称:pool-1-thread-5
线程名称:pool-1-thread-7
线程名称:pool-1-thread-6 Process finished with exit code -1
拥有公平(FIFO)和非公平(LIFO)策略,非公平侧罗会导致一些数据永远无法被消费的情况。使用SynchronousQueue阻塞队列一般要求maximumPoolSizes为无界,避免线程拒绝执行操作。SynchronousQueue没有容量,是无缓冲等待队列,是一个不存储元素的阻塞队列,会直接将任务交给消费者,必须等队列中的添加元素被消费后才能继续添加新的元素。
售票厅- LinkedBlockingQueue
public static void main(String[] args) {
// 核心线程数
int corePoolSize = 3;
//最大线程数
int maximumPoolSize = 7;
// 非核心线程的最大空闲时间
long keepAliveTime = 10L;
// 队列种类
//SynchronousQueue synchronousQueue = new SynchronousQueue<Runnable>();
LinkedBlockingQueue linkedBlockingQueue = new LinkedBlockingQueue<Runnable>();
//ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<Runnable>(5);
ThreadPoolExecutor threadpool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, linkedBlockingQueue);
for (int i = 0; i < 20; i++) {
threadpool.execute(() -> {
System.out.println("线程名称:" + Thread.currentThread().getName());
try {
Thread.sleep(50000L);
} catch (Exception ex) {
ex.printStackTrace();
}
});
System.out.println("当前线程数量:" + threadpool.getPoolSize());
System.out.println("当前队列大小:" + linkedBlockingQueue.size());
}
}
输出结果
当前线程数量:1
当前队列大小:0
当前线程数量:2
当前队列大小:0
线程名称:pool-1-thread-1
线程名称:pool-1-thread-2
当前线程数量:3
当前队列大小:0
当前线程数量:3
当前队列大小:1
当前线程数量:3
当前队列大小:2
当前线程数量:3
当前队列大小:3
当前线程数量:3
当前队列大小:4
当前线程数量:3
当前队列大小:5
当前线程数量:3
当前队列大小:6
当前线程数量:3
当前队列大小:7
线程名称:pool-1-thread-3
当前线程数量:3
当前队列大小:8
当前线程数量:3
当前队列大小:9
当前线程数量:3
当前队列大小:10
当前线程数量:3
当前队列大小:11
当前线程数量:3
当前队列大小:12
当前线程数量:3
当前队列大小:13
当前线程数量:3
当前队列大小:14
当前线程数量:3
当前队列大小:15
当前线程数量:3
当前队列大小:16
当前线程数量:3
当前队列大小:17 Process finished with exit code -1
LinkedBlockingQueue是一个无界缓存等待队列。当前执行的线程数量达到corePoolSize的数量时,剩余的任务会在阻塞队列里等待。(所以在使用此阻塞队列时maximumPoolSizes就相当于无效了),每个线程完全独立于其他线程。生产者和消费者使用独立的锁来控制数据的同步,即在高并发的情况下可以并行操作队列中的数
售票厅- ArrayBlockingQueue
public static void main(String[] args) {
// 核心线程数
int corePoolSize = 3;
//最大线程数
int maximumPoolSize = 7;
// 非核心线程的最大空闲时间
long keepAliveTime = 10L;
// 队列种类
//SynchronousQueue synchronousQueue = new SynchronousQueue<Runnable>();
//LinkedBlockingQueue linkedBlockingQueue = new LinkedBlockingQueue<Runnable>();
ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<Runnable>(5);
ThreadPoolExecutor threadpool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, arrayBlockingQueue);
for (int i = 0; i < 20; i++) {
threadpool.execute(() -> {
System.out.println("线程名称:" + Thread.currentThread().getName());
try {
Thread.sleep(50000L);
} catch (Exception ex) {
ex.printStackTrace();
}
});
System.out.println("当前线程数量:" + threadpool.getPoolSize());
System.out.println("当前队列大小:" + arrayBlockingQueue.size());
}
}
输出结果
当前线程数量:1
当前队列大小:0
线程名称:pool-1-thread-1
当前线程数量:2
当前队列大小:0
当前线程数量:3
当前队列大小:0
当前线程数量:3
当前队列大小:1
当前线程数量:3
当前队列大小:2
当前线程数量:3
当前队列大小:3
线程名称:pool-1-thread-2
当前线程数量:3
当前队列大小:4
线程名称:pool-1-thread-3
当前线程数量:3
当前队列大小:5
当前线程数量:4
当前队列大小:5
当前线程数量:5
当前队列大小:5
线程名称:pool-1-thread-4
当前线程数量:6
当前队列大小:5
线程名称:pool-1-thread-5
当前线程数量:7
当前队列大小:5
线程名称:pool-1-thread-7
线程名称:pool-1-thread-6
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task org.tonny.threads.threadpool.ThreadPool$$Lambda$1/500977346@4769b07b rejected from java.util.concurrent.ThreadPoolExecutor@cc34f4d[Running, pool size = 7, active threads = 7, queued tasks = 5, completed tasks = 0]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
at org.tonny.threads.threadpool.ThreadPool.main(ThreadPool.java:19) Process finished with exit code -1
ArrayBlockingQueue是一个有界缓存等待队列,可以指定缓存队列的大小,当正在执行的线程数等于corePoolSize时,多余的任务缓存在ArrayBlockingQueue队列中等待有空闲的线程时继续执行,当ArrayBlockingQueue已满时,会开启新的线程去执行,当线程数已经达到最大的maximumPoolSizes时,再有新的任务尝试加入ArrayBlockingQueue时会报错。
线程池ThreadPoolExecutor参数分析的更多相关文章
- 线程池ThreadPoolExecutor参数设置
线程池ThreadPoolExecutor参数设置 JDK1.5中引入了强大的concurrent包,其中最常用的莫过了线程池的实现ThreadPoolExecutor,它给我们带来了极大的方便,但同 ...
- 多线程学习笔记八之线程池ThreadPoolExecutor实现分析
目录 简介 继承结构 实现分析 ThreadPoolExecutor类属性 线程池状态 构造方法 execute(Runnable command) addWorker(Runnable firstT ...
- Java 线程池(ThreadPoolExecutor)原理分析与使用
在我们的开发中"池"的概念并不罕见,有数据库连接池.线程池.对象池.常量池等等.下面我们主要针对线程池来一步一步揭开线程池的面纱. 使用线程池的好处 1.降低资源消耗 可以重复利用 ...
- Java线程池(ThreadPoolExecutor)原理分析与使用
在我们的开发中"池"的概念并不罕见,有数据库连接池.线程池.对象池.常量池等等.下面我们主要针对线程池来一步一步揭开线程池的面纱. 使用线程池的好处 1.降低资源消耗 可以重复利用 ...
- Java 线程池(ThreadPoolExecutor)原理分析与实际运用
在我们的开发中"池"的概念并不罕见,有数据库连接池.线程池.对象池.常量池等等.下面我们主要针对线程池来一步一步揭开线程池的面纱. 有关java线程技术文章还可以推荐阅读:< ...
- Java入门系列之线程池ThreadPoolExecutor原理分析思考(十五)
前言 关于线程池原理分析请参看<http://objcoding.com/2019/04/25/threadpool-running/>,建议对原理不太了解的童鞋先看下此文然后再来看本文, ...
- Java线程池ThreadPoolExecutor使用和分析(三) - 终止线程池原理
相关文章目录: Java线程池ThreadPoolExecutor使用和分析(一) Java线程池ThreadPoolExecutor使用和分析(二) - execute()原理 Java线程池Thr ...
- Java线程池ThreadPoolExecutor使用和分析(二) - execute()原理
相关文章目录: Java线程池ThreadPoolExecutor使用和分析(一) Java线程池ThreadPoolExecutor使用和分析(二) - execute()原理 Java线程池Thr ...
- Java线程池ThreadPoolExecutor使用和分析(一)
相关文章目录: Java线程池ThreadPoolExecutor使用和分析(一) Java线程池ThreadPoolExecutor使用和分析(二) - execute()原理 Java线程池Thr ...
随机推荐
- oracle:数据库版本问题导致的bug
公司开发出来的系统,由于各现场oracle数据库版本有10.2.0.4.11.2.0.1.11.2.0.3.11.2.0.4: 进而会导致版本不一导致错误问题.下面列举2个: 1.wm_concat ...
- 【扬中集训DAY2T2】 机智的AmyZhi
[题目链接] 点击打开链接 [算法] 据说标算是暴力? 从N-200开始搜 不过我用了搜索+一些奇怪的剪枝,也A了.... [代码] 标程 #include<bits/stdc++.h> ...
- 【SOUTH CENTRAL USA 1998】 eight
[题目链接] 点击打开链接 [算法] 这是经典的八数码问题,据说此题不做人生不完整 这里笔者用的是双向广搜,由于细节较多,笔者花了3h才通过此题 [代码] #include <algorithm ...
- 【USACO】 Max Flow
[题目链接] 点击打开链接 [算法] LCA + 树上差分 [代码] #include<bits/stdc++.h> using namespace std; int i,x,y,N,K, ...
- Spss22安装与破解教程
Spss22安装与破解教程 Spss22安装与破解教程 1.下载安装包 可以去IBM官网.人大论坛等网站下载,全部文件应包括spss22安装包(含32位及64位)和破解文件,这里提供一个64位的百度网 ...
- 【前端】CentOS 7 系列教程之一: 安装 node 最新版
转载请注明出处:http://www.cnblogs.com/shamoyuu/p/linux_1.html 此系列教程从零开始,安装node.mysql.git,nginx.并且设置git自动部署. ...
- finalize方法的作用
finalize是在对象回收前做一些清扫工作,以及可清理栈上的内存,比如调用本地方法可能在栈上创建对象.即使对象不可达,也并不是非死不可,还是可以抢救一下,当一个对象没有与GCroot ...
- Epoll简介以及例子
第一部分:Epoll简介 问题 : Select,Poll和Epoll的区别 答案 : Epoll和Select的区别 1. 遍历方式的区别.select判断是否有事件发生是遍历的,而epoll是事 ...
- 洛谷 - P1337 - 平衡点/吊打XXX
一眼看过去以为是模拟退火/随机增量之类的.感觉先跑个凸包,然后在凸包内随机转移. 根据力臂长度*重量计算每个方向的分力?判断一个点比原来的点更平衡,是指他们的合力更接近0?每次判断要遍历一次,使用n的 ...
- hdu 3038 How Many Answers Are Wrong【带权并查集】
带权并查集,设f[x]为x的父亲,s[x]为sum[x]-sum[fx],路径压缩的时候记得改s #include<iostream> #include<cstdio> usi ...