AQS定义了一套多线程访问共享资源的同步器框架,许多同步类实现都依赖于它,如常用的ReentrantLock/Semaphore/CountDownLatch等等
源码
盗用一张图,来源http://www.cnblogs.com/waterystone/p/4920797.html
AQS通过维护一个private volatile int state
,并提供getState()
,setState()
,compareAndSetState()
等方法,让子类对共享变量state
进行读写,从而实现以下方法:
1. tryAcquire:获取排它锁。
2. tryRelease: 释放排它锁。
3. tryAcquireShared:获取共享锁。
4. tryReleaseShared:释放共享锁。
5. isHeldExclusively:判断是否为排它策略。
以上5个方法在ReenterLock、ReadWriteLock、CountDownLatch等类中都有实现,到时候再具体分析。
首先来看下AQS中的一个重要数据结构,Node
static final class Node {
// 共享锁节点
static final Node SHARED = new Node();
// 排它锁节点
static final Node EXCLUSIVE = null;
//---------------下面很关键-----------
// CANCELLED表示该线程不参与竞争了,只有CANCELLED>0,也只有这个状态是表示没用的node
static final int CANCELLED = 1;
// 表示该节点的下一个节点需要被唤醒
static final int SIGNAL = -1;
// 表示该节点wait condition
static final int CONDITION = -2;
// 这个状态只有共享锁有,表示共享锁需要传播
static final int PROPAGATE = -3;
// 取值为CANCELLED、SIGNAL、CONDITION、PROPAGATE、0
// 0表示啥也不是,用于初始化
volatile int waitStatus;
/**
* 前驱指针,很有用,能够将状态为CANCELLED的节点跳过,直接挂到最近的SIGNAL节点后面
*/
volatile Node prev;
/**
* 用于唤醒后继节点
*/
volatile Node next;
// 记录该节点对于的线程
volatile Thread thread;
/**
* 下一个等待condition的节点
*/
Node nextWaiter;
// 省略一下方法
}
下来看AQS中的一下几个重要方法:
- acquire
/**
* 获取排它锁,忽略中断。方法会调用tryAcquire来获取锁,如果没有获取,则会将当前线程
* 添加到阻塞队列中,期间可能会被不断阻塞,唤醒并调用tryAcquire,直到tryAcquire获取到锁
*/