J.U.C源码阅读笔记(一)AQS

AQS(AbstractQueuedSynchronizer)这个类提供了一个框架用来实现阻塞锁和一些同步工具类。比如ReentrantLockReadWriteLockSemaphoreCountDownLatchCyclicBarrier等。

AQS

1
2
3
public abstract class AbstractQueuedSynchronizer
extends AbstractOwnableSynchronizer
implements java.io.Serializable

介绍

这个类通过维护一个volatile修饰的变量state表示锁的获取情况以及一个FIFO队列用来封装要阻塞的线程。
线程通过CAS来修改state来获取锁,如果获取失败,会将当前线程封装成队列节点入队或者返回失败(tryLock())。

1
2
3
4
5
6
7
while(synchronization state does not allow acquire){

enqueue current thread if not already queued;

possibly block current thread;

}

队列中的每个节点都封装了一个没有获取到锁而被阻塞的线程,队列中的节点有多种状态,比如SIGNAL代表当前节点的后继节点被阻塞了,当释放锁时需要唤醒后继节点中的线程。CANCELLED表示当前节点中的线程超时或者被中断了,此时就会将节点的waitStatus改为CANCELLED。保证出队和入队线程安全用的锁是CLH锁,CLH是一种基于链表的高性能自旋锁。作者介绍说CLH锁相对于MCS锁比较容易处理节点的超时和取消状态。并且出队和入队由于没有锁操作,效率会更高一些。

However, they appeared more amenable than MCS for use in the synchronizer framework because they are more easily adapted to handle cancellation and timeouts, so were chosen as a basis.

Among the advantages of CLH locks are that enqueuing and dequeuing are fast, lock-free, and obstruction free (even under contention, one thread will always win an insertion race so will make progress); that detecting whether any threads are waiting is also fast (just check if head is the same as tail); and that release status is decentralized, avoiding some memory contention

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
* Status field, taking on only the values:
* SIGNAL: The successor of this node is (or will soon be)
* blocked (via park), so the current node must
* unpark its successor when it releases or
* cancels. To avoid races, acquire methods must
* first indicate they need a signal,
* then retry the atomic acquire, and then,
* on failure, block.
* CANCELLED: This node is cancelled due to timeout or interrupt.
* Nodes never leave this state. In particular,
* a thread with cancelled node never again blocks.
* CONDITION: This node is currently on a condition queue.
* It will not be used as a sync queue node
* until transferred, at which time the status
* will be set to 0. (Use of this value here has
* nothing to do with the other uses of the
* field, but simplifies mechanics.)
* PROPAGATE: A releaseShared should be propagated to other
* nodes. This is set (for head node only) in
* doReleaseShared to ensure propagation
* continues, even if other operations have
* since intervened.
* 0: None of the above
*
* The values are arranged numerically to simplify use.
* Non-negative values mean that a node doesn't need to
* signal. So, most code doesn't need to check for particular
* values, just for sign.
*
* The field is initialized to 0 for normal sync nodes, and
* CONDITION for condition nodes. It is modified using CAS
* (or when possible, unconditional volatile writes).
*/

参考