ReentrantLock非公平锁加锁源码解析

视频教程:08.040-reentrantlock-加锁成功流程

几个类和接口的关系图:
在这里插入图片描述

结合后文加锁流程一步步看,先从ReentrantLock构造器开始看,默认为非公平锁实现

在这里插入图片描述

加锁流程

1.没有竞争时(占有锁)
state:0代表没加锁,1代表已经加锁了,2代表同一个线程重入加了2次锁
head:指向 Node 队列的队头,双向队列,node内存储了对应线程信息
tail:指向 Node 队列 的队尾
exclusiveOwnerThread:表示占用锁的线程是哪个
在这里插入图片描述
2.第一个竞争出现时(发生排队)
在这里插入图片描述
Thread-1 执行了

  1. CAS 尝试将 state 由 0 改为 1,结果失败
  2. 进入 tryAcquire 加锁逻辑,这时 state 已经是1,结果仍然失败
  3. 接下来进入 addWaiter 逻辑,构造 Node 队列
    ○ 图中黄色三角表示该 Node 的 waitStatus 状态,其中 0 为默认正常状态
    ○ Node 的创建是懒惰的
    ○ 其中第一个 Node 称为 Dummy(哑元)或哨兵,用来占位,并不关联线程
    在这里插入图片描述

当前线程进入 acquireQueued 逻辑

  1. acquireQueued 会在一个死循环中不断尝试获得锁,失败后进入 park 阻塞
  2. 如果自己是紧邻着 head(排第二位),那么再次 tryAcquire 尝试获取锁,当然这时 state 仍为 1,失败
  3. 进入 shouldParkAfterFailedAcquire 逻辑,将前驱 node,即 head 的 waitStatus 改为 -1,这次返回 false

在这里插入图片描述
4. shouldParkAfterFailedAcquire 执行完毕回到 acquireQueued ,再次 tryAcquire 尝试获取锁,当然这时state 仍为 1,失败
5. 当再次进入 shouldParkAfterFailedAcquire 时,这时因为其前驱 node 的 waitStatus 已经是 -1,这次返回true
6. 进入 parkAndCheckInterrupt, Thread-1 park(灰色表示)
在这里插入图片描述

再次有多个线程经历上述过程竞争失败,变成这个样子
在这里插入图片描述
原OwnerThread释放锁时
Thread-0 释放锁,进入 tryRelease解锁流程,如果成功
● 设置 exclusiveOwnerThread 为 null
● state = 0
在这里插入图片描述

队列内线程抢到锁
当前队列不为 null,并且 head 的 waitStatus = -1,进入 unparkSuccessor 流程
找到队列中离 head 最近的一个 Node(没取消的),unpark 恢复其运行,本例中即为 Thread-1
回到 Thread-1 的 acquireQueued 流程
在这里插入图片描述

如果加锁成功(没有竞争),会设置
● exclusiveOwnerThread 为 Thread-1,state = 1
● head 指向刚刚 Thread-1 所在的 Node,该 Node 清空 Thread
● 原本的 head 因为从链表断开,而可被垃圾回收

队列外线程抢到锁
如果这时候有其它线程来竞争(非公平的体现),例如这时有 Thread-4 来了
在这里插入图片描述

如果不巧又被 Thread-4 占了先
● Thread-4 被设置为 exclusiveOwnerThread,state = 1
● Thread-1 再次进入 acquireQueued 流程,获取锁失败,重新进入 park 阻塞

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值