AbstractQueuedSynchronizer是jdk中绝大部分Lock接口实现类的一个基础抽象类,它依赖的类很少,再往深里挖也只剩下Unsafe类了,虽然本身代码量也不是很多,但足以称得起AQS框架的大名,像ReentrantLock、CountDownLatch等这类易用的工具类都是对AbstractQueuedSynchronizer进行了简单的封装,因此想要学好java并发充分理解AbstractQueuedSynchronizer类是必不可少的
API说明
依赖AbstractQueuedSynchronizer实现同步器时通常要自己实现下面几个方法才行,直接调用AbstractQueuedSynchronizer的这几个方法会抛出UnsupportedOperationException异常
方法名称 | 描述 |
---|---|
boolean tryAcquire(int arg) | 排它的获取这个状态。这个方法的实现需要查询当前状态是否允许获取,然后再进行获取(使用compareAndSetState来做)状态。 |
tryRelease(int arg) | 释放状态。 |
int tryAcquireShared(int arg) | 共享的模式下获取状态。 |
tryReleaseShared(int arg) | 共享的模式下释放状态。 |
boolean isHeldExclusively() | 在排它模式下,状态是否被占用。 |
AbstractQueuedSynchronizer的结构如下,主要由ConditionObject、Node以及一堆私有方法组成,大部分重要方法只能由他本身调用或者子类调用
直接继承AbstractQueuedSynchronizer的类主要有下面几个
ReentrantLock.Sync 公平锁与非公平锁
ReentrantReadWriteLock.Sync 读锁与写锁
Semaphore.Sync 信号量控制
ThreadPoolExecutor.Worker 信号量控制
关键方法解析:
addWaiter(Node)
private Node addWaiter(Node mode) {
//创建一个新节点,保存当前线程
Node node = new Node(Thread.currentThread(), mode);
//队列尾结点不为空 则设置新节点为尾结点,快速入队
Node pred = tail;
if (pred != null) {
node.prev = pred;
//尾结点没变时可快速入队,若是此刻尾结点被其他线程改变则只能通过enq方法补救,再次入队
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
//旧尾结点为空或者是新尾结点设置失败的补救措施
enq(node);
return node;
}
enq() addWaiter方法快速入队失败后通过本方法再次入队
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
//尾结点为空则设置一个新头结点,并将尾结点也指向它,即使两个线程同时设置了一个新节点,在进行cas比较的时候也会失败,因为compareAndSetHead方法是有旧头节点为null时才能赋值成功
if (compareAndSetHead(new Node()))
tail = head;
} else {
//此刻head肯定不为空,故队列中的有效节点的前置节点一定不为空,Node的获取前置节点为空时会抛异常,
//尾结点不为空,则将node设置为尾结点(cas执行)
node.prev = t;
if (compareAndSetTail(t, node)) {
//设置新尾结点成功后就将前置节点的指针指向新尾结点
t.next = node;
return t;
}
}
}
}
acquireQueued
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)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
shouldParkAfterFailedAcquire
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
/*
* pred节点处于发信号状态,返回true
*/
return true;
if (ws > 0) {
/*
*前置节点被取消则跳过去,将前置节点的引用前移
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
//前移后重新设置前置节点的后置节点为当前节点
pred.next = node;
} else {
/*
* 将前置节点设置为等待状态
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
parkAndCheckInterrupt 阻塞线程 检查中断状态
private final boolean parkAndCheckInterrupt() {
//阻塞当前线程
LockSupport.park(this);
return Thread.interrupted();
}
cancelAcquire 取消获取到的信号量
private void cancelAcquire(Node node) {
// Ignore if node doesn't exist
if (node == null)
return;
node.thread = null;
// Skip cancelled predecessors
Node pred = node.prev;
while (pred.waitStatus > 0)
node.prev = pred = pred.prev;
// predNext is the apparent node to unsplice. CASes below will
// fail if not, in which case, we lost race vs another cancel
// or signal, so no further action is necessary.
Node predNext = pred.next;
// Can use unconditional write instead of CAS here.
// After this atomic step, other Nodes can skip past us.
// Before, we are free of interference from other threads.
node.waitStatus = Node.CANCELLED;
// If we are the tail, remove ourselves.
if (node == tail && compareAndSetTail(node, pred)) {
compareAndSetNext(pred, predNext, null);
} else {
// If successor needs signal, try to set pred's next-link
// so it will get one. Otherwise wake it up to propagate.
int ws;
if (pred != head &&
((ws = pred.waitStatus) == Node.SIGNAL ||
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
pred.thread != null) {
Node next = node.next;
if (next != null && next.waitStatus <= 0)
compareAndSetNext(pred, predNext, next);
} else {
unparkSuccessor(node);
}
node.next = node; // help GC
}
}