非公平锁实现原理
ReentrantLock 默认是非公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
- 没有竞争时,就一个线程,加锁成功
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
// 尝试用 compareAndSet 来修改状态,0 表示未加锁,1 表示加锁
if (compareAndSetState(0, 1))
// 修改成功,把 OwnerThread 改为 currentThread
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
public final void acquire(int arg) {
// 也会尝试去获取以下锁,tryAcquire 为 true 获取到锁就不会执行 if 了
if (!tryAcquire(arg) &&
// tryAcquire 为 false,尝试创建一个 Node 节点对象加入到等待队列中
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
-
第一个竞争出现时,State状态已经为1,compareAndSetState(0, 1) 失败,进入 else 分支点进 acquire 方法
(其中第一个 Node 称为 Dummy(哑元)或哨兵,用来占位,并不关联线程) -
当前线程进入 acquireQueued 逻辑
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
// 做最后的挣扎,看能不能获取到锁
for (;;) {
final Node p = node.predecessor(); // 获取前驱节点
if (p == head && tryAcquire(arg)) { // 尝试获取锁,获取锁失败就进入下一个if
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
// shouldParkAfterFailedAcquire 获取锁失败返回 true 就阻塞,返回 false 继续循环尝试
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
进入 shouldParkAfterFailedAcquire 逻辑,将前驱 node,即 head 的 waitStatus 状态改为 -1,-1表示它有责任唤醒它的后继节点
shouldParkAfterFailedAcquire 执行完毕回到 acquireQueued ,再次 tryAcquire 尝试获取锁,当然这时state 仍为 1,失败
当再次进入 shouldParkAfterFailedAcquire 时,这时因为其前驱 node 的 waitStatus 已经是 -1,这次返回 true
进入 parkAndCheckInterrupt, Thread-1 park(灰色表示),这时候 Thread-1 就阻塞了
- 再次有多个线程经历上述过程竞争失败,变成这个样子
释放锁流程
public void unlock() {
sync.release(1);
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0) // 满足条件,唤醒下一个节点
unparkSuccessor(h);
return true;
}
return false;
}
- 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 阻塞
条件变量实现原理
每个条件变量其实就对应着一个等待队列,其实现类是 ConditionObject
await 流程
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// 当调用 await() 方法就会进入这个,这个流程就是把线程加入到条件变量的链表里面去
Node node = addConditionWaiter();
// 有可能是锁重入,把锁都释放掉
int savedState = fullyRelease(node);
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
// 当前线程 park
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
开始 Thread-0 持有锁,调用 await,进入 ConditionObject 的 addConditionWaiter 流程
创建新的 Node 状态为 -2(Node.CONDITION)表示等待,关联 Thread-0,加入等待队列尾部
接下来进入 AQS 的 fullyRelease 流程,释放同步器上的锁
unpark AQS 队列中的下一个节点,竞争锁,假设没有其他竞争线程,那么 Thread-1 竞争成功
signal 流程
public final void signal() {
// 判断是否是锁的持有线程来唤醒我
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
// 唤醒第一个
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
private void doSignal(Node first) {
do {
// 从等待链表中移除掉
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
// transferForSignal 意思是从条件等待队列转移到等待队列中,能否成功
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}