前言
AQS,AbstractQueuedSynchronizer即,抽象队列同步器。
知识点
AQS基础认知:可重入,CAS
1.什么是AQS
AQS,即AbstractQueuedSynchronizer
,本质上是JDK给我们们提供的一个核心基础类,它是juc给我们提供的很多并发工具的底层实现,如ReentrantLock
,Semaphore
,CountDownLatch
等。
一个先进先出的队列(双向链表实现) 提供公平及非公平两种实现 公平:所有线程依次进入队列有序的执行 非公平:新加入的元素会和队头元素进行资源的争抢 状态:内部通过维护一个 state
来判定是否加锁以及锁的重入。CAS:通过 state
来状态位的CAS操作来实现
2.ReentrantLock的实现(AQS)
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
ReentrantLock内部通过维护FairSync
和NonfairSync
来实现公平锁与非公平锁。两者都是Sync
的实现,而Sync
是AbstractQueuedSynchronizer
三者之间的关系如下:
- abstract static class Sync extends AbstractQueuedSynchronizer
- static final class NonfairSync extends Sync
- static final class FairSync extends Sync
2.1.公平锁加锁的实现(FairSync)
加锁
final void lock() {
acquire(1);
}
1.通过CAS操作,如果当前 state=0
,则直接修改为1,加锁成功,之后将加锁线程设置为当前线程2.若加锁失败则只需 acquire(1);
的操作
public final void acquire(int arg) {
//尝试加锁,若加锁成功,则将state=1,且加锁线程为当前线程
if (!tryAcquire(arg) &&
//当前加锁线程作为队头线程
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
//加锁失败,将当前线程挂起
selfInterrupt();
}
tryAcquire:尝试加锁
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
//第一个线程进来的时候,state=0,且
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;
}
}

可重入
刚刚线程1和线程2入队,已经模拟了线程加锁以及加锁失败线程阻塞,入队列的流程,接下来模拟先线程的可重入性。
假设此时线程1再次申请加锁
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;
}
}
先获取当前线程,并获取当前state的值,此时肯定不为0,并且current=当前加锁线程 则nextc = state+1 = 2,也就是说state的值变成2,代表当前线程重入了。state>1时代表当前线程重入次数。

释放
假如线程1此时释放锁,那么线程2就会出队变成队头元素,被唤醒

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;
}
执行流程如下:
线程1释放锁时,会将state减一, releases=1
,若线程1重入多次则需要释放多次锁,直到state=0时候,下一个线程才可以抢占锁。此时state=0,加锁线程为null,而线程2当时已被阻塞,在队列中等待,此时被唤醒后会继续获取锁。代码如下
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;
}
//当时线程2加锁时,失败,在此处被阻塞,若此时被唤醒,则会继续执行上面循环,此时获取锁成功
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
2.2.非公平锁加锁的实现(NonFairSync)
非公平锁的实现和公平锁基本一致,加锁时有区别
非公平锁在加锁时会直接申请CAS操作进行加锁,若当前锁恰好释放,则会直接抢占。
final void lock() {
//CAS操作AQS中的`state`标志,expect=0,update=1
if (compareAndSetState(0, 1))
//设置独享线程为当前线程
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
3.关于
Github: https://github.com/liangliang1259/common-notes 公众号 
文章转载自阿亮的日志,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




