目录
AbstractQueuedSynchronizer
CLH(Craig, Landin, and Hagersten locks): 是一种基于链表的可扩展、高性能、公平的自旋锁,申请线程只在本地自旋,不断轮询前驱的状态,如果前驱释放了锁就结束自旋。
用内部类Node来封装因等待权限而挂起的线程,维护一个双向链表。 使用LockSupport#unpark、LockSupport#park 来控制线程的挂起和再次执行。
static final class Node {
/** Marker to indicate a node is waiting in shared mode */
static final Node SHARED = new Node();
/** Marker to indicate a node is waiting in exclusive mode */
static final Node EXCLUSIVE = null;
/** waitStatus value to indicate thread has cancelled */
static final int CANCELLED = 1;
/** waitStatus value to indicate successor's thread needs unparking */
static final int SIGNAL = -1;
/** waitStatus value to indicate thread is waiting on condition */
static final int CONDITION = -2;
/** waitStatus value to indicate the next acquireShared should unconditionally propagate */
static final int PROPAGATE = -3;
// 节点状态
volatile int waitStatus;
// 表示的线程
volatile Thread thread;
Node的状态
- 添加到AQS链上时: 初始状态为0; 后面新添加挂起线程的节点时被更新为: SIGNAL (-1),标识有next在等待prev释放锁 。
- 大于0 只能是取消 CANCELLED (1) ;
- Node在“ConditionWaiter”链上才是 CONDITION (-2)。
- PROPAGATE (-3) 从当前测试情况来看,仅是一个过渡状态。
Node的类型
- 独占模式 EXCLUSIVE : ReentrantLock、ReentrantReadWriteLock#WriteLock ;
关键方法: AbstractQueuedSynchronizer#acquireQueued
方法#tryAcquire由具体组件来差异实现,决定当前线程是否可以拿到权限。
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)) {
// 前节点是head<前一个占锁运行的线程,现在已经释放了锁并唤醒当前线程> && 能拿到权限
setHead(node); // 将自己设置为head
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt()) // park线程
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
- 共享模式 SHARED : Semaphore、CountDownLatch、ReentrantReadWriteLock#ReadLock;
关键方法: AbstractQueuedSynchronizer#doAcquireShared
方法#tryAcquireShared也是由具体组件来差异实现,决定当前线程是否可以拿到权限。同时,这里还有一个#setHeadAndPropagate方法来控制向后传播唤醒next。
private void doAcquireShared(int arg) {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg); // 决定当前线程是否可以获取权限,并向后唤醒
if (r >= 0) {
setHeadAndPropagate(node, r); // 向后传播唤醒next
p.next = null; // help GC
if (interrupted)
selfInterrupt();
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt()) // park 线程
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
ReentrantLock独占锁
主要起作用的是它内部持有的内部类Sync
变量,该内部对象实现了抽象类AbstractQueuedSynchronizer。
实现分为:分公平锁FairSync、非公平锁NonfairSync。
- 公平锁: 优先判定 已经有其他等待线程在链头 则入链尾。
- 非公平锁: 直接compareAndSetState判定是否可以加锁。
大概逻辑如下 (见:AbstractQueuedSynchronizer#acquireQueued)
- 内部维护了一个
"int state"
, 标识被同一个线程占用了多少次,每次占用 ++ ,释放 -- ,占用N次需释放N次。- 父类
AbstractOwnableSynchronizer
里有"Thread exclusiveOwnerThread"
来记录独占<NODE.EXCLUSIVE>线程,同线程可重入。- 如果锁已经被其他线程占用,该线程被封装为Node,状态初始值为0,以
compareAndSetTail
方式入链尾,随后挂起该线程 ;同时将AQS链它前面的线程节点状态更新为Node.SIGNAL。- 能获取到锁权限:
- 当前执行线程(pre_node),它在链上此时一定是链头head。它释放锁权限后,节点状态重置为初始值0,唤醒链上next_node开始执行,见:AbstractQueuedSynchronizer#unparkSuccessor
- 该next线程获取到锁权限后,就断开与pre_node的指针关系。
线程节点在AQS链里: head.waitStatus \ head.next.waitStatus 都是 Node.SIGNAL ,只有最后tail节点还是初始值0。
指定获取锁的超时时间 ReentrantLock#tryLock(long timeout, TimeUnit unit) 原理是:
LockSupport#parkNanos(this, nanosTimeout)来约定挂起线程的时长 , 超时后会再判定一次是否能获取锁,如果还是无法独占则返回false。

ConditionObject
它是AbstractQueuedSynchronizer
的内部类, 单独维护了一个ConditionWaiter的节点链表。
与ReentrantLock合用 类似于 synchronized 和 Object.wait() \ Object.notify() \ Object.notifyAll() 的组合。
先ConditionObject#await():
- 将当前持有锁权限的线程封装为Node, 状态是:Node.CONDITION ;链入到ConditionWaiter节点链末尾。
- 释放当前线程执行锁的权限, 如果有重入则需要全部释放,记录释放权限时的
state
值。 当前线程必须持有该锁的权限,否则抛出异常IllegalMonitorStateException(见:ReentrantLock.Sync#tryRelease)。- 挂起该线程。
- 等到被
signal() | signalAll()
唤醒后,再重新去竞争锁权限,之前释放时的state值需要在重新获取权限时重设回来。
ConditionObject#awaitNanos也是使用LockSupport#parkNanos(this, nanosTimeout)来指定时间内挂起线程。
后 ConditionObject#signalAll() :(signal() 只处理第一个firstWaiter,处理过程一样。)
逐个遍历ConditionWaiter链上的所有节点
- 节点状态重置为0,重新链回到
AQS
里
等待链的末尾,并LockSupport#unpark 唤醒该线程(见: AbstractQueuedSynchronizer#transferForSignal)。 此时 ConditionObject#await()后半部分会开始执行。- 同时,也断开该节点在ConditionWaiter链上的关系。
ReentrantReadWriteLock
- 同样也分公平与不公平策略, 可重入。写锁独占, 读读并行、读写和写写按队列顺序串行 。
- ReadLock 和 WriteLock 共用同一个
Sync
, 也就是说是在同一个AQS链上排队。- state 高16位标识 read 的数量(SHARD), 低16位标识write的数量(EXCLUSIVE)。
- 写锁可以获取读锁,但读锁不能获取写锁!
Semaphore、CountDownLatch实现
Semaphore、CountDownLatch 里有它们自己的内部类Sync
的实现,也是继承自抽象父类 AbstractQueuedSynchronizer
。 不一样的是:
- 它俩将等待线程封装成 Node 类型是 SHARED 。
- 它两是非独占的 , 当 state 满足条件时,是可以依次传导向后唤醒next节点线程。
Semaphore
内部类Sync
也分公平FairSync、非公平NonfairSync,区别也是: 公平策略优先判定AQS链表已经有等待线程节点了,则先compareAndSetTail入链尾。
创建时 state设定初值N。
acquire(m)后state都减m;直到state无法满足需要信号量个数时, 创建等待节点入AQS链并挂起线程。
release(m)时,给state加m,接着唤醒next_node来拿信号量; next线程被唤醒后判定信号量是否满足:
不满足: 再次挂起。
满足: state再减去m,如果剩余的state>=0, 该next线程将唤醒next.next ;循环这个判定过程直到state无法满足时的那个线程会再次挂起。(见 AbstractQueuedSynchronizer#doAcquireShared -> #setHeadAndPropagate -> #doReleaseShared)
CountDownLatch
内部类Sync
是 static final。
创建时state设定初值N。
A线程执行await() 时: 判定 state != 0 则创建等待节点入AQS链并挂起线程。
每一次的子线程执行countDown()时: state--, 再判定若已经全部释放(state == 0) 则next_wakeup_next依次传导向下唤醒(也就是说这里会唤醒A线程)。
CyclicBarrier
private static class Generation { boolean broken = false; }
/** The lock for guarding barrier entry */
private final ReentrantLock lock = new ReentrantLock();
/** Condition to wait on until tripped */
private final Condition trip = lock.newCondition();
private final int parties; // 屏障数
private Generation generation = new Generation(); // 当前分代
private int count; // 每一个分代都会重置为parties , 每个线程执行到await()时 count--
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
// 换代
private void nextGeneration() {
// signal completion of last generation
trip.signalAll();
// set up next generation
count = parties;
generation = new Generation();
}
/** Sets current barrier generation as broken and wakes up everyone. Called only while holding lock. */
private void breakBarrier() {
generation.broken = true;
count = parties;
trip.signalAll();
}
栅栏的实现有所不同: 直接使用了ReentrantLock加锁控制并发,维护计数值count的递减 。
每个线程执行await()时:
- 先加锁 ,count --;
- 判定count != 0 时,表明还有其他线程没执行到栅栏, Condition#await() 挂起线程并释放锁;
- 直到客观上最后一个线程执行await()时, count将减至0,Condition.signalAll()唤醒所有挂起线程继续执行。
- CyclicBarrier是可以复用的,此时会重置进入nextGeneration 。

未完,待续。。。