太完整了!这是我见过最详细的线程池讲解了

Executor接口提供了将任务的执行和线程的创建以及使用解耦开来的抽象
ExecutorService接口继承了Executor接口,在Executor的基础上,增加了一些关于管理线程池本身的一些方法,比如查看任务的状态、stop/terminal线程池、获取线程池的状态等等。

2.1 ThreadPoolExecutor的构造组成

corePoolSize,核心线程数量,决定是否创建新的线程来处理到来的任务
maximumPoolSize,最大线程数量,线程池中允许创建线程地最大数量
keepAliveTime,线程空闲时存活的时间
unit,空闲存活时间单位
workQueue,任务队列,用于存放已提交的任务
threadFactory,线程工厂,用于创建线程执行任务
handler,拒绝策略,当线程池处于饱和时,使用某种策略来拒绝任务提交

public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)

2.2 线程池的生命周期

2.2.1 线程池五种状态
image.png

2.2.2 线程池生命周期流转

image

2.2.3 ThreadPoolExecutor中表示线程池状态设计

在ThreadPoolExecutor中使用一个AtomicInteger类型的ctl字段来描述线程池地运行状态和线程数量,通过ctl的高三位来表示线程池的5种状态,低29位表示线程池中现有的线程数量。使用最少的变量来减少锁竞争,提高并发效率。

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// 线程池线程数地bit数
private static final int COUNT_BITS = Integer.SIZE - 3;
// 线程池中最大线程容量
private static final int CAPACITY = (1 << COUNT_BITS) - 1;

// runState is stored in the high-order bits
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;

// 获取线程池地运行状态
private static int runStateOf(int c) { return c & ~CAPACITY; }
// 获取有效工作线程地数量
private static int workerCountOf(int c) { return c & CAPACITY; }
// 组装线程数量和线程池状态
private static int ctlOf(int rs, int wc) { return rs | wc; }

2.3 线程池地执行流程

1)如果workerCount < corePoolSize ==> 创建线程执行提交的任务
2)如果workerCount >= corePoolSize && 阻塞队列未满 ==> 添加至阻塞队列,等待后续线程来执行提交地任务
3)如果workerCount >= corePoolSize && workerCount < maxinumPoolSize && 阻塞队列已满 ==> 创建非核心线程执行提交的任务
4)如果workerCount >= maxinumPoolSize && 阻塞队列已满 ==> 执行拒绝策略

image

2.3.1 execute 提交任务

public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
// 工作线程数量 < corePoolSize => 直接创建线程执行任务
if (workerCountOf© < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
// 工作线程数量 >= corePoolSize && 线程池处于运行状态 => 将任务添加至阻塞队列中
if (isRunning© && workQueue.offer(command)) {
int recheck = ctl.get();
/**

  • 为什么需要double check线程池地状态?
  • 在往阻塞队列中添加任务地时候,有可能阻塞队列已满,需要等待其他的任务移出队列,在这个过程中,线程池的状态可能会发生变化,所以需要doublecheck
  • 如果在往阻塞队列中添加任务地时候,线程池地状态发生变化,则需要将任务remove
    */
    if (! isRunning(recheck) && remove(command))
    reject(command);
    else if (workerCountOf(recheck) == 0)
    addWorker(null, false);
    }
    else if (!addWorker(command, false))
    reject(command);
    }

2.3.2 addWorker 创建线程加入线程池

private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;😉 {
int c = ctl.get();
int rs = runStateOf©;

// Check if queue empty only if necessary.
// 线程池状态处于非RUNNING状态,添加worker失败
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
// 判断线程池中线程数量是否处于该线程池允许的最大线程数量,如果允许创建线程,则cas更新线程池中线程数量,并退出循环检查,执行下面创建线程地逻辑
for (;😉 {
int wc = workerCountOf©;
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
if (compareAndIncrementWorkerCount©)
break retry;
c = ctl.get(); // Re-read ctl
if (runStateOf© != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}

boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
// 创建线程
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int rs = runStateOf(ctl.get());
// 如果线程池处于RUNNING状态,并且线程已经启动则提前抛出线程异常启动异常
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
// 将线程加入已创建地线程集合,更新用于追踪线程池中线程数量largestPoolSize字段
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
// 启动线程执行任务
if (workerAdded) {
// 启动线程会调用Worker中地runWorker()来执行任务
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}

2.3.3 runWorker 执行任务

final void runWorker(Worker w) {
// 获取执行任务线程
Thread wt = Thread.currentThread();
// 获取执行任务
Runnable task = w.firstTask;
// 将worker中的任务置空
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) {
w.lock();
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

Java核心架构进阶知识点

面试成功其实都是必然发生的事情,因为在此之前我做足了充分的准备工作,不单单是纯粹的刷题,更多的还会去刷一些Java核心架构进阶知识点,比如:JVM、高并发、多线程、缓存、Spring相关、分布式、微服务、RPC、网络、设计模式、MQ、Redis、MySQL、设计模式、负载均衡、算法、数据结构、kafka、ZK、集群等。而这些也全被整理浓缩到了一份pdf——《Java核心架构进阶知识点整理》,全部都是精华中的精华,本着共赢的心态,好东西自然也是要分享的

image

image

image

内容颇多,篇幅却有限,这就不在过多的介绍了,大家可根据以上截图自行脑补
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
oCoP-1712905794110)]

[外链图片转存中…(img-AcPm8XV5-1712905794110)]

内容颇多,篇幅却有限,这就不在过多的介绍了,大家可根据以上截图自行脑补
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
线程池是一种常的并发编程技术,可以提高程序的性能和响应速度。它通过创建一定数量的线程,并将任务分配给这些线程来执行,从而减少线程的创建和销毁所带来的开销,提高系统的效率和稳定性。 线程池的基本构成包括任务队列、工作线程池和管理器。任务队列用于存储待执行的任务,工作线程池用于执行任务,管理器用于管理线程池的状态和任务分配。 在线程池启动时,会创建一定数量的工作线程,并将它们放入空闲队列中。当有任务提交时,管理器将任务添加到任务队列中,空闲线程从队列中取出任务并执行。当所有的线程都在执行任务时,新的任务将被暂存到任务队列中,等待空闲线程的出现。 线程池的优点是可以避免线程创建和销毁的开销,提高应用程序的性能和响应速度;可以控制线程的数量和执行状态,避免线程过多或过少所带来的问题;可以通过合理的任务分配和调度,提高系统的效率和稳定性。 线程池的缺点是需要占用一定的系统资源,包括内存和CPU资源;需要对任务的执行时间和线程的数量进行合理的配置,否则可能会导致系统的瓶颈和性能下降;需要对任务队列的大小和任务的优先级进行合理的设置,否则可能会导致任务执行的不公平和延迟。 总之,线程池是一种常的并发编程技术,可以提高系统的效率和稳定性,但需要合理的配置和设计,才能发挥其最大的优势。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值