线程池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 ...
随机推荐
- Git 使用的问题总结
1.git stash pop 显示 xxx already exists, no checkout 当我们先使用 git stash save -u '保存信息说明' 来储藏更改,然后拉取代码 gi ...
- luogu P1036 选数 x
P1036 选数 题目描述 已知 n 个整数 x1,x2,…,xn,以及一个整数 k(k<n).从 n 个整数中任选 k 个整数相加,可分别得到一系列的和.例如当 n=4,k=3,4 个整数分别 ...
- 小程序swiper实现订单页面
小程序swiper实现订单页面 myOrder.wxml <!--pages/myorder/myorder.wxml--> <view class="swiper-tab ...
- [CSP-S模拟测试]:array(单调栈)
题目描述 在放完棋子之后,$dirty$又开始了新的游戏. 现在他拥有一个长为$n$的数组$A$,他定义第$i$个位置的分值为$i−k+1$,其中$k$需要满足: 对于任意满足$k\leqslant ...
- svn 服务器操作
mkdir /var/svn/svnrepos/aaasvnadmin create /var/svn/svnrepos/aaasvnserve -d -r /var/svn/svnrepos #启动 ...
- 高通平台Camera调试(一)【转】
本文转载自:http://www.voidcn.com/blog/Winva/article/p-6044730.html 4.3. Camera 参考文档: 1) 80-NA157-22_PRESE ...
- MK66FN2M0VLQ18
NXP Kinetis K66: 180MHz Cortex-M4F MCU, 2MB Flash, 256KB SRAM, Dual USBs (FS + HS), Ethernet, 144-LQ ...
- find查找特殊权限用法
find查找特殊权限的用法 find選項與參數: 3. 與檔案權限及名稱有關的參數: -name filename:搜尋檔案名稱為 filename 的檔案: -size [+-]SIZE:搜尋比 S ...
- 十三、python列表方法汇总
'''1.append():更新列表'''l=[]l.append('111')l.append('[123,456]')print l-------------------------------- ...
- CTEX WinEdt 改变默认 pdf viewer
CTEX 2.9.2, WinEdt 7.0 "Options" -> "Excution Modes..." -> "PDF viewe ...