AQS非公平锁实现原理
加锁解锁流程
先从构造器开始看,默认为非公平锁实现
public ReentrantLock() { sync = new NonfairSync(); }
NonfairSync 继承自 AQS
没有竞争时(占有锁)
第一个竞争出现时(发生排队)
Thread-1 执行了
-
先执行了lock方法,里面CAS 尝试将 state 由 0 改为 1,结果失败
final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); }
-
再执行acquire方法,进入 tryAcquire 逻辑,这时 state 已经是1,结果仍然失败
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
-
接下来进入 addWaiter 逻辑,构造 Node 队列
private Node addWaiter(Node mode) { Node node = new Node(Thread.currentThread(), mode); // Try the fast path of enq; backup to full enq on failure Node pred = tail; if (pred != null) { node.prev = pred; if (compareAndSetTail(pred, node)) { pred.next = node; return node; } } enq(node); return node; }
-
-
图中黄色三角表示该 Node 的 waitStatus 状态,其中 0 为默认正常状态
-
Node 的创建是懒惰的
-
其中第一个 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)) { setHead(node); p.next = null; // help GC failed = false; return interrupted; } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } }
-
acquireQueued 会在一个死循环中不断尝试获得锁,失败后进入 park 阻塞
-
如果自己是紧邻着 head(排第二位,这里是head就是指哑元),那么再次 tryAcquire 尝试获取锁,当然这时 state 仍为 1,失败
-
进入 shouldParkAfterFailedAcquire 逻辑,将前驱 node,即 head 的 waitStatus 改为 -1,这次返回 false
-
shouldParkAfterFailedAcquire 执行完毕回到 acquireQueued ,再次 tryAcquire 尝试获取锁,当然这时state 仍为 1,失败
-
当再次进入 shouldParkAfterFailedAcquire 时,这时因为其前驱 node 的 waitStatus 已经是 -1,这次返回true
-
进入 parkAndCheckInterrupt, Thread-1 park(灰色表示)
再次有多个线程经历上述过程竞争失败,变成这个样子,头就是null,尾就是Thread-3
原OwnerThread释放锁时
Thread-0 释放锁,进入 tryRelease 流程,如果成功
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; }
-
设置 exclusiveOwnerThread 为 null
-
state = 0
protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; }
队列内线程抢到锁
当前队列不为 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 阻塞
所有源码调用过程一个一个函数及其分析写在下面这篇文章中