Ch5-Java Lock 之 AQS

Ch5-Java Lock 之 AQS

January 2, 2020
Java | JUC
java

AQS 即 java.util.concurrent.locks.AbstractQueuedSynchronizer,可以用来构建锁和同步器的框架,使用 AQS 能简单且高效地构造出应用广泛的大量的同步器。

1. 介绍 #

AbstractQueuedSynchronizer 主要维护了两个队列(Sync Queue, Condition Queue)和一个临界变量(state)。

  • Sync Queue 采用的是 CLH(Craig,Landin,and Hagersten) 虚拟双向队列,AQS 将每条请求共享资源的线程封装成一个 CLH 锁队列的一个结点 (Node) 来实现锁的分配。
  • Condition Queue 是一个单向链表,只有当使用 Condition 时,才会存在此单向链表,并且可能会有多个。
  • state!=0 代表当前对象锁已经被占有,其他线程来加锁时则会失败,失败的线程会被放到 Sync Queue 中。state 的操作都是通过 CAS 机制来保证修改的安全性。

CLH 锁 Craig、Landin and Hagersten 是一种基于链表的可扩展、高性能、公平的自旋锁,申请线程只在本地变量上自旋,它不断轮询前驱的状态,如果发现前驱释放了锁就结束自旋。

AQS Queues

2. 实现的同步工具 #

同步工具 同步工具与 AQS 的关联
ReentrantLock 使用 state 保存锁重复持有的次数。当一个线程获取锁时,ReentrantLock 记录当前获得锁的线程标识,用于检测是否重复获取,以及错误线程试图解锁操作时异常情况的处理。
Semaphore 使用 state 来保存信号量的当前计数。tryRelease 会增加计数,acquireShared 会减少计数。
CountDownLatch 使用 state 来表示计数。计数为 0 时,所有的 Acquire 操作(CountDownLatch 的 await 方法)才可以通过。
ReentrantReadWriteLock 使用 state 的前 16 位保存写锁持有的次数,后 16 位用于保存读锁的持有次数。
ThreadPoolExecutor Worker 利用 state 同步状态实现对独占线程变量的设置(tryAcquire 和 tryRelease)。

3. 参考文献 #