概述
AQS,AbstractQueuedSynchronizer,是一个抽象类,定义了同步状态的获取和释放方法来供自定义的同步组件使用,AQS的实现依赖于内部的同步队列(FIFO),当线程获取同步状态失败后就会被封装成一个Node节点加入同步队列的尾部,并阻塞该线程,当同步状态释放时唤醒队列头节点。
AQS中最重要的三个成员变量
private transient volatile Node head;
private transient volatile Node tail;
private volatile int state;
state为0时表示同步状态可用,state>0时表示同步状态已被占用。
1、ReentrantLock中的非公平锁与AQS
非公平锁,NonfairSync,继承了ReentrantLock内部的Sync,而Sync又继承了AQS。
NonfairSync 的lock()实现
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
分析:
①、首先通过CAS尝试将state的值从0设置为1,如果成功就将占用锁的线程设置为当前线程,如果失败调用acquire(1)方法,这里使用的compareAndSetState方法是继承自AQS中的方法,底层是本地方法。
②、如果CAS将state从0修改到1失败,则调用acquire()方法,这里使用的是继承自AQS中的方法,如下:
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
tryAcquire方法在非公平锁中的实现如下:
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
如果当前state为0,并且能够通过CAS修改为args(这里为1),则将占用锁的线程设置为当前线程,返回true;否则判断占用锁的线程是否是当前线程,如果是就将state加上arges,并判断state是否溢出,若不溢出设置state并返回true;否则返回false。
addWaiter方法,AQS的方法
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
参数mode为独占模式,tail为同步队列尾,刚开始为null,直接进入enq()方法,enq()方法如下:
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
enq方法内部是一个死循环,第一次因为taile为null所以t为null,通过CAS的方式新建一个空节点,并将head和tail都指向它,使用CAS的目的是为了防止多个线程在进行到这一步时创建多个队列;第二次循环时tail不为null,将当前线程的prev置为tail,然后使用CAS的方式将tail指向node,并返回node。
acquireQueued方法,addWait返回了插入的节点作为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);
}
}
获取p为插入节点的前置节点,这里是head,因此p == head成立,调用tryAcquire()方法,如果tryAcquire成功,则进入if块,将node设置为头节点,并将node的前置节点的next置为null,如下所示:
因此只有队列的第二个节点有机会争用锁,第三及以后的节点的prev不为head,会进行shouldParkAfterFailedAcquire方法,第二个节点争用失败后也是调用此方法,
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
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;
}
shouldParkAfterFailedAcquire是一个判断争用锁的线程是否应该被阻塞的方法,如果当前节点的前置节点的状态为Node.SIGNAL,可以安全阻塞。
如果前置节点的状态大于0,也就是CANCELLED时,则向后循环找到第一个不为CANCELLED的节点作为当前节点的前置节点,返回false,其实就是删除CANCELLED节点,如果shouldParkAfterFailedAcquire为true则会调用parkAndCheckInterrupt方法
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
通过 LockSupport.park(this);将当前线程挂起到waiting状态。
ReentrantLock的unlock()实现
public void unlock() {
sync.release(1);
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
Node s = node.next;
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);
}
释放锁时将state减掉releases,如果为0返回true,然后unparkSuccessor方法真正释放锁,获取head节点的next节点,如果不为空通过LockSupport.unpark(s.thread)释放对应的被挂起的线程。