OpenJDK: JUC locks

ReentrantLock 公平锁和非公平锁的实现

如果需要长时间等待,AQS 总是会将等待线程加入到队列尾部,唤醒时总是唤醒队首线程。这样做能够保证已经被睡眠的线程必定按照顺序唤醒。这样做难道不是永远都是公平锁?

不是!NonfairSync 在 tryAcquire() 时不会检查是否为队首。这意味着如果有队列之外的线程尝试获取锁(发生在刚刚调用 ReentrantLock.lock() 的阶段),可能会先于队首线程获得锁。虽然这种情况的发生非常需要巧合,但也是不公平的; FairSync 对这一巧合下的公平性做出了更高的要求。

公平和不公平的主要区别在于等待队列外的线程和等待队列上的线程之间的公平性。

CountDownLatch

只有 countDown() 被调用给定的次数后,await() 才能被唤醒。

synchronize 关键字

synchronize 关键字对应的对象锁是不公平的。锁的是对象,信息存储在对象头中。有锁升级过程:偏向锁(JDK 15 中已废弃)、轻量锁、重量锁。

AQS 实现可重入锁

AQS 维护了一个 int 类型的 state 和一个双端等待队列。state 含义随实现不同而不同。在可重入场景下,state 数值表示已重入的次数,比如 state 为 2 表示已经重入了 2 次,为 0 表示尚未加锁。