AQS(AbstractQueuedSynchronizer)
整理不易,如果文章对您有益,麻烦给点个赞,收藏一下,防止走丢
AQS是线程队列同步器,用来构建锁或者其它同步器组件的重要级基础框架及整个JUC体系的基石,通过内置的FIFO队列来完成资源获取线程的排队工作,并通过一个int类型变量表示持有锁的状态。
对于ReentranLock等,是面向锁的使用者,而AQS是面向锁的实现者。
如果共享资源被占用,就需要一定的阻塞等待唤醒机制来保证锁的分配。这个机制主要用的是CLH队列的变体实现的,将暂时获取不到锁的线程加入到队列中,这个队列就是AQS的抽象表现。它将请求共享资源的线程封装成队列的节点(Node),通过CAS、自旋以及LockSupport.park()的方式,维护state变量的状态,使并发达到同步的控制效果。
以ReentranLock的加解锁作为切入点认识AQS
在ReentranLock类内部有AQS的实现子类,并按照公平和非公平锁,分成两个实现子类。
大致结构如下
public class ReentrantLock{
private final Sync sync;
// AQS子类
abstract static class Sync extends AbstractQueuedSynchronizer {
}
// 非公平锁具体实现子类
static final class NonfairSync extends Sync {
}
// 公平锁具体实现子类
static final class FairSync extends Sync {
}
}
接下来,以加解锁两个过程来探寻一下AQS的作用机制。
加锁
ReentranLock的加锁,对于使用者来说,非常简单。
ReentrantLock lock = new ReentrantLock();
lock.lock();
其中lock方法:
public void lock() {
sync.lock();
}
加锁方法就是直接调用AQS的lock方法,然后再根据ReentranLock采用的公平锁或非公平锁提供具体实现。ReentranLock默认是非公平锁。
非公平锁Lock()
final void lock() {
// 尝试将锁的状态,由0改变为1,其实就是一直尝试抢占锁的动作
if (compareAndSetState(0, 1))
// 如果成功修改锁状态,说明抢占成功,将当前线程设置成执行线程
setExclusiveOwnerThread(Thread.currentThread());
else
// 获得锁
acquire(1);
}
公平锁Lock()
final void lock() {
// 获得锁
acquire(1);
}
从上面两种锁策略的lock代码中,可以看到非公平锁,一开始就尝试自行抢占。
acquire(1)方法
public final void acquire(int arg) {
// 产生获取锁
if (!tryAcquire(arg) &&
// 入队
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
tryAcquire(arg)又重新尝试获取锁,并根据公平锁和非公平锁进行些许不同的操作。
非公平锁tryAcquire(arg)
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;
}
公平锁tryAcquire(arg)
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
// 判断锁是空闲
if (c == 0) {
// 判断当前线程是不是队列中第一个等待线程
if (!hasQueuedPredecessors() &&
// 抢占线程
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
// 如果当前线程是执行线程,进行再次加锁
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
公平锁tryAcquire(arg)与非公平锁tryAcquire(arg)的唯一区别在于公平锁多了一个hasQueuedPredecessors() 方法。
addWaiter(Node.EXCLUSIVE)
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;
}
进行将线程入队,如果队列不为空,则添加到队尾,如果队列为空,则调用enq方法创建初始节点并入队。
enq(node)代码
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;
}
}
}
}
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
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;
}
// 判断是否应该被park(休眠) 并进行休眠
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
shouldParkAfterFailedAcquire(p, node)
判断是否在抢占失败后进行park
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
if (ws > 0) {
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/*
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
parkAndCheckInterrupt()
park当前线程
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
解锁
ReentranLock的解锁,对于使用者来说,也非常简单。
lock.unlock();
其中unlock()方法
public void unlock() {
sync.release(1);
}
release(int arg)
释放锁
public final boolean release(int arg) {
// 尝试释放
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
tryRelease(arg)
尝试释放
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;
}