AbstractQueuedSynchronizer作为java.util.concurrent包的基础,它提供了一套完整的同步编程框架,开发人员只需要实现其中几个简单的方法就能自由的使用诸如独占,共享,条件队列等多种同步模式。我们常用的比如ReentrantLock等基础类库都是基于AQS实现的,我们开发人员更应该了解它的实现原理,这样才能在使用过程中得心应手。
下面是获取同步锁的源码流程:(前提是了解下同步器流程以及CAS操作原理)
/**
* 通过一次调用来实现,共享锁获取模式,忽略中断。如果返回则代表成功,否则当前线程
* 会在队列中自旋,直至成功返回。tryAcquireShared(arg) 返回的值如果<0则,代表获取锁失败。
* 需要进入队列
*
* @param arg the acquire argument. This value is conveyed to
* {@link #tryAcquireShared} but is otherwise uninterpreted
* and can represent anything you like.
*/
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
/**
* 尝试在共享模式下获取锁,该方法将会查询验证当前线程对象是否在共享模式中被获取,如果允
* 许将会获取锁。继续执行
* @返回值的几种状态:小于0获取失败;大于0则唤醒当前节点后所有可以唤醒的节点;等于0只能
* 唤醒头节点之后的一个节点,也就是独占该锁;
*/
protected int tryAcquireShared(int arg) {
throw new UnsupportedOperationException();
}
/**
* 不间断的获取锁。
*/
private void doAcquireShared(int arg) {
//新建共享节点,并加入队列尾部
final Node node = addWaiter(Node.SHARED);
//默认获取锁状态失败
boolean failed = true;
try {
//等待线程被中断标记位
boolean interrupted = false;
for (;;) {
//当前节点的前驱节点
final Node p = node.predecessor();
//如果是头节点(头节点代表是占用锁的节点)
if (p == head) {
int r = tryAcquireShared(arg);
//再次尝试获取锁,返回值大于0,也就是允许唤醒当前节点,
//以及后续节点
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
if (interrupted)
selfInterrupt();
failed = false;
return;
}
}
//前继节点非head节点,将前继节点状态设置为SIGNAL,通过park挂起node节点
//的线程
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
/**
* 在共享模式下,设置队列的头,并检查后续节点是否在等待,(前提:参数propagate>0
* 或当前节点waitStatus为PROPAGATE)态。
* 自此传入的第一个node参数为新建的,获取共享锁的线程节点。
*/
private void setHeadAndPropagate(Node node, int propagate) {
//纪录老的头节点
Node h = head; // Record old head for check below
setHead(node);
/**
* 调用发方指示传播,尝试传递下个队列节点:
* 头节点后面的节点需要被唤醒(waitStatus<0)
* propagate > 0 表示调用方指明了后继节点需要被唤
*
*/
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
Node s = node.next;
//如果当前节点的后继节点是共享类型或者没有后继节点,则进行唤醒
if (s == null || s.isShared())
//如果head节点状态为SIGNAL,唤醒head节点线程,重置head.waitStatus->0
//head节点状态为0(第一次添加时是0),设置head.waitStatus设置为
//Node.PROPAGATE表示状态需要向后继节点传播
doReleaseShared();
}
}
/**
* 唤醒操作
*/
private void doReleaseShared() {
for (;;) {
//纪录此时的头节点地址
Node h = head;
//当前头不为空,并且不是最后元素
if (h != null && h != tail) {
int ws = h.waitStatus;
//满足唤醒的条件
if (ws == Node.SIGNAL) {
//设置当前节点的状态为0
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; //如果设置失败,重新循环
//上述成功设置为0后,进行唤醒,如果头节点的下个节点获取成功
//头节点就不会变换,继续执行,不回执行到 if (h == head)
unparkSuccessor(h);
}
//(如果本身头节点的waitStatus是出于重置状态(waitStatus==0)的,将其
//设置为“传播”状态。
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}
/**
* 继续唤醒后续节点,如果存在。
*/
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
Node s = node.next;
//晒除前置节点为空,或者状态为"cancle"的节点,保证前驱节点的有效性。
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
//执行唤醒线程操作
LockSupport.unpark(s.thread);
}