面试官:你给我说一下线程池里面的几个锁吧。 (下)

简介: 面试官:你给我说一下线程池里面的几个锁吧。 (下)

image.png

好了,前面说了这么多,你只要记住一个大前提:自定义 worker 类的大前提是为了维护中断状态,因为正在执行任务的线程是不应该被中断的。

接着往下看注释:

We implement a simple non-reentrant mutual exclusion lock rather than use ReentrantLock because we do not want worker tasks to be able to reacquire the lock when they invoke pool control methods like setCorePoolSize.

这里解释了为什么老爷子不用 ReentrantLock 而是选择了自己搞一个 worker 类。

因为他想要的是一个不能重入的互斥锁,而 ReentrantLock 是可以重入的。

从前面分析的这个方法也能看出来,是一个非重入的方法:


image.png


传进来的参数根本没有使用,代码里面也没有累加的逻辑。

如果你还没反应过来是怎么回事的话,我给你看一下 ReentrantLock 里面的重入逻辑:

image.png

传进来的参数根本没有使用,代码里面也没有累加的逻辑。

如果你还没反应过来是怎么回事的话,我给你看一下 ReentrantLock 里面的重入逻辑:

image.png

你看到了吗,有一个累加的过程。

释放锁的时候,又有一个与之对应的递减的过程,减到 0 就是当前线程释放锁成功:

image.png

而上面的累加、递减的逻辑在 worker 类里面通通是没有的。

那么问题又来了:如果是可以重入的,会发生什么呢?

目的还是很前面一样:不想打断正在执行任务的线程。

同时注释里面提到了一个方法:setCorePoolSize。

你说巧不巧,这个方法我之前写线程池动态调整的时候重点讲过呀:

image.png

可惜当时主要讲 delta>0 里面的的逻辑去了。

现在我们看一下我框起来的地方。

workerCountOf(ctl.get()) > corePoolSize 为 true 说明什么情况?

说明当前的 worker 的数量是多于我要重新设置的 corePoolSize,需要减少一点。

怎么减少呢?

调用 interruptIdleWorkers 方法。

这个方法我们前面刚刚分析了,我再拿出来一起看一下:

image.png

里面有个 tryLock,如果是可以重入的,会发生什么情况?

是不是有可能把正在执行的 worker 给中断了。

这合适吗?

image.png

好了,注释上的最后一句话:

Additionally, to suppress interrupts until the thread actually starts running tasks, we initialize lock state to a negative value, and clear it upon start (in runWorker).

这句话就是说为了在线程真正开始运行任务之前,抑制中断。所以把 worker 的状态初始化为负数(-1)。

大家要注意这个:and clear it upon start (in runWorker).

在启动的时候清除 it,这个 it 就是值为负数的状态。

老爷子很贴心,把方法都给你指明了:in runWorker.

所以你去看 runWorker,你就知道为什么这里上来先进行一个 unLock 操作,后面跟着一个 allow interrupts 的注释:

image.png

因为在这个地方,worker 的状态可能还是 -1 呢,所以先 unLock,把状态刷到 0 去。

同时也就解释了前面我没有解释的 -1 是哪里来的:

image.png

想明白了吗,-1 是哪里来的?

肯定是在启动过程中,执行了 workers.add 方法,但是还没有来得及执行 runWorker 方法的 worker 对象,它们的状态就是 -1。

image.png


最后说一句


好了,看到了这里了,点赞安排一个吧。写文章很累的,需要一点正反馈。

给各位读者朋友们磕一个了:

微信图片_20220428213536.jpg

目录
相关文章
|
16天前
|
并行计算 算法 安全
面试必问的多线程优化技巧与实战
多线程编程是现代软件开发中不可或缺的一部分,特别是在处理高并发场景和优化程序性能时。作为Java开发者,掌握多线程优化技巧不仅能够提升程序的执行效率,还能在面试中脱颖而出。本文将从多线程基础、线程与进程的区别、多线程的优势出发,深入探讨如何避免死锁与竞态条件、线程间的通信机制、线程池的使用优势、线程优化算法与数据结构的选择,以及硬件加速技术。通过多个Java示例,我们将揭示这些技术的底层原理与实现方法。
68 3
|
2月前
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
|
15天前
|
Java 关系型数据库 MySQL
【JavaEE“多线程进阶”】——各种“锁”大总结
乐/悲观锁,轻/重量级锁,自旋锁,挂起等待锁,普通互斥锁,读写锁,公不公平锁,可不可重入锁,synchronized加锁三阶段过程,锁消除,锁粗化
|
2月前
|
供应链 安全 NoSQL
PHP 互斥锁:如何确保代码的线程安全?
在多线程和高并发环境中,确保代码段互斥执行至关重要。本文介绍了 PHP 互斥锁库 `wise-locksmith`,它提供多种锁机制(如文件锁、分布式锁等),有效解决线程安全问题,特别适用于电商平台库存管理等场景。通过 Composer 安装后,开发者可以利用该库确保在高并发下数据的一致性和安全性。
41 6
|
3月前
|
NoSQL Java API
美团面试:Redis锁如何续期?Redis锁超时,任务没完怎么办?
在40岁老架构师尼恩的读者交流群中,近期有小伙伴在面试一线互联网企业时遇到了关于Redis分布式锁过期及自动续期的问题。尼恩对此进行了系统化的梳理,介绍了两种核心解决方案:一是通过增加版本号实现乐观锁,二是利用watch dog自动续期机制。后者通过后台线程定期检查锁的状态并在必要时延长锁的过期时间,确保锁不会因超时而意外释放。尼恩还分享了详细的代码实现和原理分析,帮助读者深入理解并掌握这些技术点,以便在面试中自信应对相关问题。更多技术细节和面试准备资料可在尼恩的技术文章和《尼恩Java面试宝典》中获取。
美团面试:Redis锁如何续期?Redis锁超时,任务没完怎么办?
|
3月前
|
运维 API 计算机视觉
深度解密协程锁、信号量以及线程锁的实现原理
深度解密协程锁、信号量以及线程锁的实现原理
55 2
|
3月前
|
存储 Kubernetes 架构师
阿里面试:JVM 锁内存 是怎么变化的? JVM 锁的膨胀过程 ?
尼恩,一位经验丰富的40岁老架构师,通过其读者交流群分享了一系列关于JVM锁的深度解析,包括偏向锁、轻量级锁、自旋锁和重量级锁的概念、内存结构变化及锁膨胀流程。这些内容不仅帮助群内的小伙伴们顺利通过了多家一线互联网企业的面试,还整理成了《尼恩Java面试宝典》等技术资料,助力更多开发者提升技术水平,实现职业逆袭。尼恩强调,掌握这些核心知识点不仅能提高面试成功率,还能在实际工作中更好地应对高并发场景下的性能优化问题。
|
3月前
|
Java 应用服务中间件 测试技术
Java21虚拟线程:我的锁去哪儿了?
【10月更文挑战第8天】
58 0
|
3月前
|
安全 调度 数据安全/隐私保护
iOS线程锁
iOS线程锁
35 0
|
3月前
|
Java API
【多线程】乐观/悲观锁、重量级/轻量级锁、挂起等待/自旋锁、公平/非公锁、可重入/不可重入锁、读写锁
【多线程】乐观/悲观锁、重量级/轻量级锁、挂起等待/自旋锁、公平/非公锁、可重入/不可重入锁、读写锁
50 0