文章目录
一、ReentrantLock原理
二、加锁执行流程
1、非公平锁实现原理(ReentrantLock默认实现的原理)
NonfairSync继承自AQS
没有竞争时加锁成功 执行
第一个竞争出现时 if中的语句块执行失败,执行else中的acquire
进入acquire中又一次执行失败,因为state一直是1,结果任然失败,接着就进入addWaiter中的逻辑,构造Node队列
当线程进入acquireQueuded逻辑
-
acquireQueued 会在一个死循环中不断尝试获得锁,失败后进入 park 阻塞
-
如果自己是紧邻着 head(排第二位),那么再次 tryAcquire 尝试获取锁,当然这时 state 仍为 1,失败
-
进入 shouldParkAfterFailedAcquire 逻辑,将前驱 node,即 head 的 waitStatus 改为 -1,这次返回 false
下图中的state为1表示获得了锁,state为-1表示当下一个节点进入阻塞队列时有义务去唤醒在阻塞中状态为0的节点,正常状态下为0;
-
shouldParkAfterFailedAcquire 执行完毕回到 acquireQueued ,再次 tryAcquire 尝试获取锁,当然这时 state 仍为 1,失败
-
当再次进入 shouldParkAfterFailedAcquire 时,这时因为其前驱 node 的 waitStatus 已经是 -1,这次返回 true
-
线程进入 parkAndCheckInterrupt中阻塞, Thread-1 park(灰色表示)
-
当多个线程经历了失败就变成下图这个样子
除了最后一个节点,其他的waitState都被改成了-1,-1代表有责人唤醒自己的下一个节点
三、ReentraLock释放锁流程(非公平锁)
Thread-0释放锁,进入图一tryRelease流程,如果成功
设置execlusiveOwnerThread为null,将state设置为0
如果当前队列不为 null,并且 head 的 waitStatus = -1,进入 unparkSuccessor 流程
找到队列中离 head 最近的一个 Node),unpark 恢复其运行,本图二中即为 Thread-1
如果Thread-1加锁成功(),没有竞争会设置
exclusiveOwnerThread 为 Thread-1,state = 1
现正的节点指向Thread-1的结点,此时会把,原来的头结点断开(可以被垃圾回收处理点),把Thread-1所在的Node清空,让Thread-1原来所在的节点为头结点。
如果此时Thread-4来和Thread-1竞争,不是队列中的线程,由非公平锁性值产生的竞争。
如果被Thread-4先占领,Thread被设置为execlusiveOwnerThread,state=1
Thread-1再次进入acquiredQued流程,获取锁失败,重新进入park阻塞
四、ReentraLock可重入原理
锁重入或加锁时让state竞争,释放锁时让state减为0
五、ReentraLock可打断原理
1、不可打断模式
Thread.intettupted会清除打断标记
不清除打断标记,下次park的时候park会失效
在此模式下,即使它被打断,仍会驻留在 AQS 队列中,一直要等到获得锁后方能得知自己被打断了
2、可打断模式
如果park被打断直接抛出异常,不会继续循环