从源码角度来分析线程池-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 ...
随机推荐
- Thymeleaf中model设一个值 页面显示此值 JS取此值
model设值: m.addAttribute("pageNo", pageNo); 页面显示值: 当前为第:<span th:text="${pageNo}&qu ...
- 转载:[Oracle]杀死正在执行的sql语句
地址:https://www.jianshu.com/p/7ad9ce2db55c 还未尝试,试后再来总结. 2020年2月12日 20点19分 试了,不好用.
- JVM 中的对象及引用
JVM中对象的创建过程 对象的内存分配 虚拟机遇到一条 new 指令时,首先检查是否被类加载器加载,如果没有,那必须先执行相应的类加载过程. 类加载就是把 class 加载到 JVM 的运行时数据区的 ...
- 转载:Linux: What’s the difference between a soft link and a hard link?
Link:https://www.moreofless.co.uk/linux-difference-soft-symbolic-link-and-hard-link/ This example sh ...
- ICARUS主题美化
Icarus用户指南 - 主题美化 Icarus的主题样式编码文件为themes/icarus/layout/layout.jsx. 此文件定义了站点全局的样式设置.本文详细介绍了本主题针对文章分类的 ...
- CTF-WeChall-第二天
2020.09.10 奥力给,举步维艰的时候就是要一边做一遍记,虽然慢但是不要嫌弃,要不然就是举步不前
- outh2
之前做天猫精灵对接,就碰到了outh鉴权,当时实现好之后没有细细缕,今天看了一个博主的介绍,贴一下 转载自http://www.ruanyifeng.com/blog/2014/05/oauth_2_ ...
- 【转】Locust性能-零基础入门系列(3)-压力权重
本文将继续对Locust性能测试进行持续讲解,主要是讲解虚拟用户数分配和权重的关系.在locust file中进行多用户类的实现和操作.我们这次先上完整的代码: from locust import ...
- linux学习(十一)linux安装nginx
一.前言 由于本地练手的小demo用的是vue+spring boot来玩的,所以部署的时候想着用Nginx来实现反向代理[即请求转发,解决前后端分离的跨域请求问题],既然要用,那么首先得在服务器上面 ...
- MySQL中的临时表到底什么是?
Author:极客小俊 一个专注于web技术的80后 我不用拼过聪明人,我只需要拼过那些懒人 我就一定会超越大部分人! CSDN@极客小俊,原创文章, B站技术分享 B站视频 : Bilibili.c ...