
🌟我的其他文章也讲解的比较有趣😁,如果喜欢博主的讲解方式,可以多多支持一下,感谢🤗!
🌟了解 ThreadLocal请看: ThreadLocal有趣讲解,小白也能听懂!
其他优质专栏: 【🎇SpringBoot】【🎉多线程】【🎨Redis】【✨设计模式专栏(已完结)】...等
如果喜欢作者的讲解方式,可以点赞收藏加关注,你的支持就是我的动力
✨更多文章请看个人主页: 码熔burning
想象一下,有一个很受欢迎的公共厕所 🚽,同一时间只能一个人进去。
ReentrantLock
就好比是这个厕所的门锁管理员。他负责管理谁能进去。
深入了解 ReentrantLock 请看:ReentrantLock:可定制的"VIP 包间"
核心原理:AQS
ReentrantLock
的底层依赖一个叫做 AQS 的框架。你可以把 AQS 理解为一个通用的排队和状态管理系统。
- 状态 (State): AQS 内部有一个
state
变量(是个整数)。在ReentrantLock
里:state = 0
: 表示厕所现在没人,门是空闲的 ✅。state > 0
: 表示厕所有人,门被占用 了 🔒。这个数字还表示同一个人重复进入 (重入)了多少次。比如一个人进去后,又在里面锁了一层门,state
就变成 2。
- 等待队列 (Queue): AQS 维护了一个等待队列 。这个队列像银行排队的队伍一样,是先进先出 (FIFO) 的 🚶♂️🚶♀️🚶♂️。想上厕所但发现里面有人的人(线程),就会被安排到这个队列里排队等着。
非公平锁 (Nonfair Lock) - 默认模式
- 解释: 就像一个秩序不太好 的厕所。
- 当你(线程)想上厕所时,你首先 会冲到门口 🏃💨,猛地推一下门 ,看看是不是正好没人(尝试用 CAS 原子操作直接把
state
从 0 改成 1)。 - 如果正好没人,恭喜你 🎉,你直接就进去了!哪怕旁边已经有人在排队等了很久,你也可能因为动作快而"插队"成功。
- 如果里面有人 (推门失败,
state
不是 0),或者你尝试抢锁的那一下正好别人也抢成功了,那你没办法 😟,只能乖乖去队伍(AQS 队列)后面排着。 - 当里面的人出来(释放锁)时,管理员(AQS)会唤醒 ⏰ 队伍最前面的人。但是,与此同时 ,如果又有一个新人跑过来直接推门 🏃💨,并且正好成功了,那这个刚被唤醒、正准备进去的人可能又得等一下。
- 当你(线程)想上厕所时,你首先 会冲到门口 🏃💨,猛地推一下门 ,看看是不是正好没人(尝试用 CAS 原子操作直接把
- 底层实现关键点:
- 调用
lock()
时,先尝试直接获取锁 (CAS 修改state
)。 - 获取失败,才把自己加入 AQS 等待队列。
- 释放锁时,唤醒队头节点,但新来的线程仍有机会抢先获取锁。
- 调用
- 优点: 可能性能更好,吞吐量更高 🚀。因为减少了线程挂起和唤醒的次数(如果运气好直接抢到锁,就不用排队和被唤醒了)。
- 缺点: 可能导致饥饿 😩。排在前面的线程可能一直等不到锁,因为总有新来的线程"插队"成功。
公平锁 (Fair Lock)
- 解释: 就像一个非常有秩序 的厕所 👍。
- 当你(线程)想上厕所时,你首先会看一眼 👀 队伍前面有没有人排队 (
hasQueuedPredecessors()
检查)。 - 如果队伍里有人 ,对不起 🙅♂️,你不能直接去推门 ,必须老老实实去队伍(AQS 队列)后面排着 🚶♂️🚶♀️。
- 只有当队伍是空的 ,你才可以去尝试推门 (尝试 CAS 修改
state
)。 - 当里面的人出来(释放锁)时,管理员(AQS)只会唤醒队伍最前面 的那个人,并且只有这个人能进去。新来的人?对不起,看队伍里有人,请自觉排队。
- 当你(线程)想上厕所时,你首先会看一眼 👀 队伍前面有没有人排队 (
- 底层实现关键点:
- 调用
lock()
时,先检查 AQS 队列中是否有等待者。 - 如果有等待者,则不尝试获取锁,直接加入队列尾部。
- 只有当队列为空时,才尝试获取锁。
- 释放锁时,严格唤醒并让队头节点获取锁。
- 调用
- 优点: 公平 ⚖️,保证了先来后到,不会有线程饿死。
- 缺点: 性能相对较低,吞吐量可能不如非公平锁 📉。因为即使锁是空闲的,只要队列里有人,新来的线程也得去排队,导致更多的线程挂起和唤醒,增加了上下文切换的开销。
总结一下 ↔️:
ReentrantLock
通过内部的 Sync
类(它继承了 AQS)来实现锁逻辑 🛠️。Sync
有两个子类:NonfairSync
和 FairSync
。
- 核心区别 在于尝试获取锁 (
tryAcquire
方法) 时的行为:NonfairSync
: 直接尝试 CAS 修改state
,失败再入队。FairSync
: 先检查队列是否为空或者自己是不是队头,满足条件才尝试 CAS 修改state
,否则直接入队。
🤔 默认情况下,new ReentrantLock()
创建的是非公平锁 ,因为它通常有更好的性能。如果你需要保证公平性,可以使用 new ReentrantLock(true)
来创建公平锁。