从源码角度来分析线程池-ThreadPoolExecutor实现原理
- 降低了资源的消耗:通过池化技术,重复利用已创建好的线程。
- 增加了响应的速度:若有空闲线程时,直接执行任务,无需等待创建新的线程。
- 增加了系统的稳定性和可管理性:对系统而言,过多的线程会导致资源调度失衡,降低了系统的稳定性。线程池进行统一的管理(调优,监控和分配等),减少碎片化信息。
I. 线程池的类关系图

- Executor接口只有一个execute()方法,将任务的提交和运行进行解耦。
- ExecutorService接口在Executor的基础上,增加了生命周期的控制(线程池状态转换)和submit()方法生成Future结果。
- AbstractExecutorService是一个抽象类,实现了ExecutorService接口中的submit()方法,并实现了任务的执行流程。
- ThreadPoolExecutor主要实现两个功能:线程池生命周期管理,任务的执行execute()方法。
II. 生命周期管理
- workerCount: 表示线程池中有效的线程数量
- runState: 表示线程池当前的运行状态
ctl信息

COUNT_BITS=29(十进制)
CAPACITY=0000 1111 1111 1111 1111 1111 1111 1111(二进制)

信息获取:
int c = ctl.get();
workerCount = workerCountOf(c); //ctl的低28位表示线程数量
runState = runStateOf(c); //ctl的高四位表示状态
运行状态

- RUNNING: 可以接受新的任务请求,也可处理阻塞队列中的任务
- SHUTDOWN: 不接受新的任务请求,但会处理阻塞队列中的任务
- STOP: 不接受新的任务请求,阻塞队列也会直接清空,正在处理的任务也会被直接中断
- TIDYING: 所有的任务都已经终止,线程池中不存在有效线程
- TERMINATED: 线程池终止
III. 运行机制

- 任务请求
- 任务分配
- 添加worker
- 运行worker
- 任务拒绝
任务请求
- void execute(Runnable command):不需要获取任务结果。
- <T> Future<T> submit(Callable<T> task):需要获取任务结果。
任务分配
- 线程池线程数<核心线程数:创建一条新的线程,并在该线程上直接执行任务;
- 线程池线程数>=核心线程数 && 阻塞队列未满: 将任务推入阻塞队列中,并创建一条新的线程(若此时线程池存在有效线程则不创建),该线程获取阻塞队列头部的任务并执行;
- 线程池线程数>=核心线程数 && 阻塞队列已满 && 线程池线程数<最大线程数:创建一条新的线程,并在该线程直接执行任务;
- 线程池线程数>最大线程数 && 阻塞队列已满:任务拒绝。
添加worker
- firstTask:新创建线程执行的第一个任务,这里特指新提交的任务
- core:ture表示核心线程数,false表示最大线程数
运行worker
任务拒绝
获取任务结果
IV.实际案例
submit(Callable task)
public class MultiThreadPool {
private static List<String> hello = Arrays.asList("h", "e", "l", "l", "o");
private static String task(String args) {
System.out.println(String.format("submit - thread name: %s, args: %s", Thread.currentThread().getName(), args));
return args;
}
private static void submitTask() throws InterruptedException, ExecutionException, TimeoutException {
List<Future> futures = new ArrayList<>();
final ThreadPoolExecutor executor = new ThreadPoolExecutor(4, 6, 10L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(), new ThreadPoolExecutor.CallerRunsPolicy());
try {
for (String str : hello) {
Thread.sleep(1);
Future f = executor.submit(() -> task(str));
futures.add(f);
}
for (Future f: futures) {
String result = (String) f.get(60, TimeUnit.SECONDS);
System.out.println(String.format("submit - thread name: %s, result: %s", Thread.currentThread().getName(), result));
}
} finally {
executor.shutdown();
}
}
public static void main(String[] args) throws Exception {
submitTask();
}
}
输出结果:
submit - thread name: pool-1-thread-3, args: l
submit - thread name: pool-1-thread-1, args: h
submit - thread name: pool-1-thread-4, args: l
submit - thread name: pool-1-thread-2, args: e
submit - thread name: pool-1-thread-3, args: o
submit - thread name: main, result: h
submit - thread name: main, result: e
submit - thread name: main, result: l
submit - thread name: main, result: l
submit - thread name: main, result: o
execute(Runnable task)
public class MultiThreadPool {
private static List<String> hello = Arrays.asList("h", "e", "l", "l", "o");
private static class Task implements Runnable {
private String arg;
Task(String arg) {
this.arg = arg;
}
public void run() {
System.out.println(String.format("execute - thread name: %s, args: %s", Thread.currentThread().getName(), arg));
}
}
private static void executeTask() throws InterruptedException, ExecutionException, TimeoutException {
Map<String, Future> futureMap = new HashMap<>();
final ThreadPoolExecutor executor = new ThreadPoolExecutor(4, 6, 10L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(), new ThreadPoolExecutor.CallerRunsPolicy());
try {
for (String str : hello) {
Thread.sleep(1);
executor.execute(new Task(str));
}
} finally {
executor.shutdown();
}
}
public static void main(String[] args) throws Exception {
executeTask();
}
}
输出结果:
execute - thread name: pool-1-thread-3, args: l
execute - thread name: pool-1-thread-1, args: h
execute - thread name: pool-1-thread-4, args: l
execute - thread name: pool-1-thread-2, args: e
execute - thread name: pool-1-thread-3, args: o
从源码角度来分析线程池-ThreadPoolExecutor实现原理的更多相关文章
- Java并发包源码学习系列:线程池ThreadPoolExecutor源码解析
目录 ThreadPoolExecutor概述 线程池解决的优点 线程池处理流程 创建线程池 重要常量及字段 线程池的五种状态及转换 ThreadPoolExecutor构造参数及参数意义 Work类 ...
- Java并发包源码学习系列:线程池ScheduledThreadPoolExecutor源码解析
目录 ScheduledThreadPoolExecutor概述 类图结构 ScheduledExecutorService ScheduledFutureTask FutureTask schedu ...
- JUC源码学习笔记5——线程池,FutureTask,Executor框架源码解析
JUC源码学习笔记5--线程池,FutureTask,Executor框架源码解析 源码基于JDK8 参考了美团技术博客 https://tech.meituan.com/2020/04/02/jav ...
- 《java.util.concurrent 包源码阅读》13 线程池系列之ThreadPoolExecutor 第三部分
这一部分来说说线程池如何进行状态控制,即线程池的开启和关闭. 先来说说线程池的开启,这部分来看ThreadPoolExecutor构造方法: public ThreadPoolExecutor(int ...
- Java8线程池ThreadPoolExecutor底层原理及其源码解析
小侃一下 日常开发中, 或许不会直接new线程或线程池, 但这些线程相关的基础或思想是非常重要的, 参考林迪效应; 就算没有直接用到, 可能间接也用到了类似的思想或原理, 例如tomcat, jett ...
- jdk线程池ThreadPoolExecutor工作原理解析(自己动手实现线程池)(一)
jdk线程池ThreadPoolExecutor工作原理解析(自己动手实现线程池)(一) 线程池介绍 在日常开发中经常会遇到需要使用其它线程将大量任务异步处理的场景(异步化以及提升系统的吞吐量),而在 ...
- 线程池ThreadPoolExecutor使用原理
本文来源于翁舒航的博客,点击即可跳转原文观看!!!(被转载或者拷贝走的内容可能缺失图片.视频等原文的内容) 若网站将链接屏蔽,可直接拷贝原文链接到地址栏跳转观看,原文链接:https://www.cn ...
- 21.线程池ThreadPoolExecutor实现原理
1. 为什么要使用线程池 在实际使用中,线程是很占用系统资源的,如果对线程管理不善很容易导致系统问题.因此,在大多数并发框架中都会使用线程池来管理线程,使用线程池管理线程主要有如下好处: 降低资源消耗 ...
- 源码解读 TDengine 中线程池的实现
这篇文章中提到了 tsched 的源码可以一读,所以去阅读了一下,总共220来行. 1. 阅读前工作 通过上文了解到这段程序实现的是一个任务队列,同时带有线程池.这段程序是计算机操作系统里经典的con ...
随机推荐
- Kubernetes 存活、就绪探针
在设计关键任务.高可用应用程序时,弹性是要考虑的最重要因素之一. 当应用程序可以快速从故障中恢复时,它便具有弹性. 云原生应用程序通常设计为使用微服务架构,其中每个组件都位于容器中.为了确保Kuber ...
- 没事也来配一个logback
工程下载:https://files.cnblogs.com/files/xiandedanteng/logbackCfg20200115.zip 首先创建一个maven项目,pom.xml如下书写: ...
- [Java数据结构]Queue
Queue扩展了Collection,它添加了支持根据先进先出FIFO原则对元素排序的方法. 当对Queue调用add和offer方法时,元素始终添加在Queue的末尾:要检索一个元素,就要使用一个元 ...
- PHP对象传值 - 引用传值
对象传值本质上是引用传值,将一个对象变量($a)赋值给另个变量($b),实际上是将$a存储的对象内存引用地址赋值$b,此时两个变量指向的就是一个对象.其中一个变量发送改变,另一个也会跟着改变.和引用变 ...
- 微信小程序爬坑记
1.this.setData修改数组里的值1).data: { hide:[true,true] },this.setData({ 'hide[0]': false});2).var str = &q ...
- Linux:apache安装
1.查询是否已安装 rpm -qa httpd 如果已安装,先卸载 发现有依赖包,先把依赖卸载 或者加上--nodeps参数,不考虑依赖,直接卸载 rpm -e --nodeps httpd-2. ...
- JS语法_类型
类型 JS 的数据类型 boolean number string undefined null symbol object TS 额外的数据类型 void BigInt 是一种内置对象,它提供了一种 ...
- jmeter连数据库
前提:jmeter不能直接连数据库,需要导入一个jar包 步骤: 1.右键线程组--添加--配置元件--JDBC Connection Configuration 2.jdbc的基本配置:可以修改jd ...
- python测试http、websocket接口
测试环境有个项目需要每天构造数据,来尽量保证测试环境和生产环境数据量保持一致.需要生成订单后商家接单完成,以下是代码,主要是用接口完成 创建订单 # coding=utf-8 import reque ...
- golang 协程学习
协程数据传递问题 func TestGoroutineData(t *testing.T) { var wg sync.WaitGroup wg.Add(1) i := 0 go func(j int ...