在线客服
扫描二维码
下载博学谷APP
扫描二维码
关注博学谷微信公众号
ThreadPoolExecutor里面使用到JUC同步器框架AbstractQueuedSynchronizer、大量的位操作、CAS操作。ThreadPoolExecutor提供了固定活跃线程、额外的线程、任务队列以及拒绝策略这几个重要的功能。下面我们一起来看看Java 线程池ThreadPoolExecutor的原理解析。

1、JUC同步器框架
ThreadPoolExecutor里面使用到JUC同步器框架,主要用于四个方面:
(1)全局锁mainLock成员属性,是可重入锁ReentrantLock类型,主要是用于访问工作线程Worker集合和进行数据统计记录时候的加锁操作。
(2)条件变量termination,Condition类型,主要用于线程进行等待终结awaitTermination()方法时的带期限阻塞。
(3)任务队列workQueue,BlockingQueue类型,任务队列,用于存放待执行的任务。
(4)工作线程,内部类Worker类型,是线程池中真正的工作线程对象。
2、核心线程
这里先参考ThreadPoolExecutor的实现并且进行简化,实现一个只有核心线程的线程池,要求如下:暂时不考虑任务执行异常情况下的处理;任务队列为无界队列;线程池容量固定为核心线程数量;暂时不考虑拒绝策略。
public class CoreThreadPool implements Executor {
private BlockingQueue<Runnable> workQueue;
private static final AtomicInteger COUNTER = new AtomicInteger();
private int coreSize;
private int threadCount = 0;
public CoreThreadPool(int coreSize) {
this.coreSize = coreSize;
this.workQueue = new LinkedBlockingQueue<>();
}
@Override
public void execute(Runnable command) {
if (++threadCount <= coreSize) {
new Worker(command).start();
} else {
try {
workQueue.put(command);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
}
}
private class Worker extends Thread {
private Runnable firstTask;
public Worker(Runnable runnable) {
super(String.format("Worker-%d", COUNTER.getAndIncrement()));
this.firstTask = runnable;
}
@Override
public void run() {
Runnable task = this.firstTask;
while (null != task || null != (task = getTask())) {
try {
task.run();
} finally {
task = null;
}
}
}
}
private Runnable getTask() {
try {
return workQueue.take();
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
}
public static void main(String[] args) throws Exception {
CoreThreadPool pool = new CoreThreadPool(5);
IntStream.range(0, 10)
.forEach(i -> pool.execute(() ->
System.out.println(String.format("Thread:%s,value:%d", Thread.currentThread().getName(), i))));
Thread.sleep(Integer.MAX_VALUE);
}
}
某次运行结果如下:
Thread:Worker-0,value:0
Thread:Worker-3,value:3
Thread:Worker-2,value:2
Thread:Worker-1,value:1
Thread:Worker-4,value:4
Thread:Worker-1,value:5
Thread:Worker-2,value:8
Thread:Worker-4,value:7
Thread:Worker-0,value:6
Thread:Worker-3,value:9
设计此线程池的时候,核心线程是懒创建的,如果线程空闲的时候则阻塞在任务队列的take()方法,其实对于ThreadPoolExecutor也是类似这样实现,只是如果使用了keepAliveTime并且允许核心线程超时则会使用BlockingQueue#poll进行轮询代替永久阻塞。
3、其他附加功能
构建ThreadPoolExecutor实例的时候,需要定义maximumPoolSize(线程池最大线程数)和corePoolSize(核心线程数)。当任务队列是有界的阻塞队列,核心线程满负载,任务队列已经满的情况下,会尝试创建额外的maximumPoolSize - corePoolSize个线程去执行新提交的任务。当ThreadPoolExecutor这里实现的两个主要附加功能是:
(1)一定条件下会创建非核心线程去执行任务,非核心线程的回收周期(线程生命周期终结时刻)是keepAliveTime,线程生命周期终结的条件是:下一次通过任务队列获取任务的时候并且存活时间超过keepAliveTime。
(2)提供拒绝策略,也就是在核心线程满负载、任务队列已满、非核心线程满负载的条件下会触发拒绝策略。
以上就是Java 线程池ThreadPoolExecutor的原理解析,大家都看懂了吗?如果想要深入学习更多关于Java 线程池的内容,欢迎大家在博学谷报名在线课程进行学习~
— 申请免费试学名额 —
在职想转行提升,担心学不会?根据个人情况规划学习路线,闯关式自适应学习模式保证学习效果
讲师一对一辅导,在线答疑解惑,指导就业!
相关推荐 更多
HTML5是什么?HTML5用来做什么?
HTML5是什么?HTML5用来做什么?HTML5是HTML的修订版本,HTML5并不是对HTML4、XHTML的革命,原来的HTML4开发的HTML网页同样可用;开发者严格按照代码规范,使用XHTML严格、规范、语法,可按XHTML的严格要求来开发HTML5。
9167
2019-06-18 14:57:54
如何用Redis轻松实现秒杀系统?
如何用Redis轻松实现秒杀系统?一般来说有三个办法,即写入内存而不是写入硬盘;异步处理而不是同步处理;分布式处理。相信只要大家做好以上这三点,就能轻松用Redis轻松实现秒杀系统。下面本文将从秒杀的定义,秒杀系统场景特点,秒杀架构设计理念,架构方案和实际案例讲解等方面,为大家介绍如何实现秒杀系统。
7864
2019-11-04 15:00:18
Java学习注意哪些问题?学习少踩坑
Java学习注意哪些问题?学习少踩坑,很多人学习JAVA时都会遇到很多问题,但是这些问题大多数是因为自身的原因导致的,我们一起来看看学习JAVA的“三不要”。
5980
2020-06-17 14:58:25
JVM内存区域复习汇总
相信绝大所数的开发求职者在面试中,总能遇到面试官问JVM内存区域的相关知识点。今天小编就来和大家一起复习一遍JVM内存区域,主要内容包括内存区域的划分、运行数据区、生命周期以及了解JVM内存的方法。
5958
2020-07-16 14:48:51
Java语言适合零基础入门为什么?
很多人在选择入门IT行业,不知道自己适合学习哪一门编程语言,也不知道哪一门语言的发展前景好。编程语言有很多种,但选择一门编程语言非常值得认真考虑的,选太容易的担心后面学其他的语言会很难,选太难的话又担心自己不会,不少人选择性Java入门,Java语言好在哪儿呢?
5743
2020-07-29 11:11:29
