线程池ThreadPoolExecutor实现原理
线程属于稀缺资源,对于线程的创建规则,引用《阿里巴巴 Java 手册》中的一条进行说明。
本篇从源码方面介绍ThreadPoolExecutor对象,并简要解析线程池工作原理。
首先ThreadPoolExecutor中定义了几个线程池状态常量。
- // runState is stored in the high-order bits
- private static final int RUNNING = - << COUNT_BITS;
- private static final int SHUTDOWN = << COUNT_BITS;
- private static final int STOP = << COUNT_BITS;
- private static final int TIDYING = << COUNT_BITS;
- private static final int TERMINATED = << COUNT_BITS;
- RUNNING是运行状态,线程池可以接收新任务
- SHUTDOWN是在调用shutdown()方法以后处在的状态。表示不再接收新任务,但队列中的任务可以执行完毕
- STOP是在调用shutdownNow()方法以后的状态。不再接收新任务,中断正在执行的任务,抛弃队列中的任务
- TIDYING表示所有任务都执行完毕
- TERMINATED为中止状态,调用terminated()方法后,尝试更新为此状态
看一下构造方法的参数
- public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,
- ThreadFactory threadFactory, RejectedExecutionHandler handler) {
- }
- corePoolSize是线程池的核心线程数
- maximumPoolSize是线程池允许的最大线程数
- keepAliveTime为线程空闲时的存活时间
- unit是keepAliveTime的单位
- workQueue是用来保存等待被执行的线程的队列
- threadFactory,线程工厂,通常使用默认工厂,定义了线程名称生成规则。
- handler是当最大线程数和队列都满了以后,线程池的处理策略
这里可以简单看下JDK中已有的4种饱和策略handler:
- AbortPolicy:默认策略,直接抛出异常,throw new RejectedExecutionException
- CallerRunsPolicy:如果线程池没有中止,直接用调用者的线程资源执行任务
- DiscardOldestPolicy:如果线程池没有中止,移除队列第一个任务,再执行当前任务
- DiscardPolicy:什么也不做,直接抛弃这个任务
也可以自定义饱和策略,只需实现RejectedExecutionHandler接口。
再看一下JDK中的workQueue队列:
- ArrayBlockingQueue:基于数组实现
- LinkedBlockingQueue:基于链表实现,默认容量Integer.MAX_VALUE
- SynchronousQuene:不存储元素,每个插入操作必须等待另一个线程调用移除操作
- priorityBlockingQuene:具有优先级的队列
JDK提供了Executors工厂类。这里面有几种实例化线程池的方法:
- public static ExecutorService newFixedThreadPool(int nThreads) {
- return new ThreadPoolExecutor(nThreads, nThreads,
- 0L, TimeUnit.MILLISECONDS,
- new LinkedBlockingQueue<Runnable>());
- }
指定了线程数,且corePoolSize == maximumPoolSize。
- public static ExecutorService newCachedThreadPool() {
- return new ThreadPoolExecutor(, Integer.MAX_VALUE,
- 60L, TimeUnit.SECONDS,
- new SynchronousQueue<Runnable>());
- }
可缓存线程池。最大线程数达到Integer.MAX_VALUE。所以在使用该线程池时,一定要控制并发数,不然会创建很多线程,占用大量资源。
- public static ExecutorService newSingleThreadExecutor() {
- return new FinalizableDelegatedExecutorService
- (new ThreadPoolExecutor(, ,
- 0L, TimeUnit.MILLISECONDS,
- new LinkedBlockingQueue<Runnable>()));
- }
只有一个线程的线程池,可以保证提交任务的顺序执行。
上面的实例方法都很方便,但是在开发中创建线程池时,最好不好使用Executors类中的初始化方法。见《阿里巴巴 Java 手册》:
最后看一下ThreadPoolExecutor执行任务的方法
- public void execute(Runnable command) {
- if (command == null)
- throw new NullPointerException();
- int c = ctl.get();
- if (workerCountOf(c) < corePoolSize) {
- if (addWorker(command, true))
- return;
- c = ctl.get();
- }
- if (isRunning(c) && workQueue.offer(command)) {
- int recheck = ctl.get();
- if (! isRunning(recheck) && remove(command))
- reject(command);
- else if (workerCountOf(recheck) == )
- addWorker(null, false);
- }
- else if (!addWorker(command, false))
- reject(command);
- }
- 判断command是否为空
- 获取线程状态
- 计算线程池中的线程数量,如果数量小于corePoolSize,就创建一个新线程执行任务
- 如果线程池正在运行状态,且写入队列成功。
- 再次获取线程池状态。判断,如果线程状态变成了非运行状态,就从队列中移除任务,调用reject()方法执行饱和策略handler
- 如果线程池为空,就创建一个新线程执行任务
- 如果第4步判断没有通过,尝试建立线程执行任务,若没有成功,就执行饱和策略handler
以一张简单的流程图描述上面的步骤:
线程池ThreadPoolExecutor实现原理的更多相关文章
- jdk线程池ThreadPoolExecutor工作原理解析(自己动手实现线程池)(一)
jdk线程池ThreadPoolExecutor工作原理解析(自己动手实现线程池)(一) 线程池介绍 在日常开发中经常会遇到需要使用其它线程将大量任务异步处理的场景(异步化以及提升系统的吞吐量),而在 ...
- 21.线程池ThreadPoolExecutor实现原理
1. 为什么要使用线程池 在实际使用中,线程是很占用系统资源的,如果对线程管理不善很容易导致系统问题.因此,在大多数并发框架中都会使用线程池来管理线程,使用线程池管理线程主要有如下好处: 降低资源消耗 ...
- Java8线程池ThreadPoolExecutor底层原理及其源码解析
小侃一下 日常开发中, 或许不会直接new线程或线程池, 但这些线程相关的基础或思想是非常重要的, 参考林迪效应; 就算没有直接用到, 可能间接也用到了类似的思想或原理, 例如tomcat, jett ...
- 线程池ThreadPoolExecutor工作原理
前言 工作原理 如果使用过线程池,细心的同学肯定会注意到,new一个线程池,但是如果不往里面提交任何任务的话,main方法执行完之后程序会退出,但是如果向线程池中提交了任务的话,main方法执行完毕之 ...
- 线程池ThreadPoolExecutor使用原理
本文来源于翁舒航的博客,点击即可跳转原文观看!!!(被转载或者拷贝走的内容可能缺失图片.视频等原文的内容) 若网站将链接屏蔽,可直接拷贝原文链接到地址栏跳转观看,原文链接:https://www.cn ...
- 从源码角度来分析线程池-ThreadPoolExecutor实现原理
作为一名Java开发工程师,想必性能问题是不可避免的.通常,在遇到性能瓶颈时第一时间肯定会想到利用缓存来解决问题,然而缓存虽好用,但也并非万能,某些场景依然无法覆盖.比如:需要实时.多次调用第三方AP ...
- Java线程池ThreadPoolExecutor使用和分析(三) - 终止线程池原理
相关文章目录: Java线程池ThreadPoolExecutor使用和分析(一) Java线程池ThreadPoolExecutor使用和分析(二) - execute()原理 Java线程池Thr ...
- Java 线程池(ThreadPoolExecutor)原理分析与使用
在我们的开发中"池"的概念并不罕见,有数据库连接池.线程池.对象池.常量池等等.下面我们主要针对线程池来一步一步揭开线程池的面纱. 使用线程池的好处 1.降低资源消耗 可以重复利用 ...
- Java 线程池(ThreadPoolExecutor)原理解析
在我们的开发中“池”的概念并不罕见,有数据库连接池.线程池.对象池.常量池等等.下面我们主要针对线程池来一步一步揭开线程池的面纱. 有关java线程技术文章还可以推荐阅读:<关于java多线程w ...
随机推荐
- [LightOJ1240]Point Segment Distance 题解
题意简述 原题LightOJ 1240,Point Segment Distance(3D). 求三维空间里线段AB与C. 题解 我们设一个点在线段AB上移动,然后发现这个点与原来的C点的距离呈一个单 ...
- sh_03_注释
sh_03_注释 # 这是第一个注释 print("hello hello") """ 这是一个多行注释 .... .... .... 注释结束了 & ...
- 洛谷P1199 三国游戏——题解
题目传送 显然,在这样的数据范围下搜索是没希望的了.好好分析一下,发现小涵时不可能拿到与一个武将最默契的另一个武将了.所以考虑一下默契值次大的一对武将. 显然,对每一个武将来说,小涵是可以拿到默契值次 ...
- Anaconda-navigator 打不开的解决方法(亲测有效!)
本文链接:https://blog.csdn.net/qq_42489092/article/details/92208822method_1:每当你打不开应用时,不妨试一下:用管理员身份运行 请用管 ...
- Cmdow-一个win32窗口管理命令行工具
最近有个需求,将同一个程序运行8个实例,并按照规则在两个窗口上分布,本以为用bat就可以实现,结果发现没那么容易,搜了很久找到了这个工具cmdow.exe,发现这个东西真不错. 符合了我们项目的需求: ...
- django搭建一个小型的服务器运维网站
前言 不管是运维还是开发抑或是测试,工作中不免会和Linux服务器打交道,常见的操作譬如:查看CPU或内存状态.查看和修改服务器时间.查看或者修改服务器配置文件.实时查看或回看系统的日志.重启服务 ...
- slider组件
slider组件,是一个强大的滑动选择器组件: 属性: min:类型 数字 滑动选择器的(范围)最小值 max:类型 数字 滑动选择器的(范围)最大值 step:类型 数字 步长(滑一次走的距离) ...
- 建立起BI的支撑团队
Bobby Luo 罗如意(18907295660@189.cn) 2011年7月 http://weibo.com/cquptvlry 电子商务中的BI应用初探 系统架构 对整个数据仓库的架构进行规 ...
- mysql_存储引擎层-innodb buffer pool
buffer pool 是innodb存储引擎带的一个缓存池,查询数据时,首先从内存中查询 数据如果内存中存在的话直接返回. innodb buffer pool 和 qcache 的区别:Qcach ...
- (转)Intellij IDEA 自动生成 serialVersionUID
转自 : https://blog.csdn.net/tiantiandjava/article/details/8781776 Setting->Inspections->Seriali ...