1、什么是AQS
AQS(AbstractQueuedSynchronizer)
,所谓的AQS
即是抽象的队列式的同步器,内部定义了很多锁相关的方法,我们熟知的ReentrantLock
、ReentrantReadWriteLock
、CountDownLatch
、Semaphore
等都是基于AQS
来实现的。
AQS的核心思想是,如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制AQS是用CLH队列锁实现的,即将暂时获取不到锁的线程加入到队列中。
2、AQS实现原理
AQS
中 维护了一个volatile int state
(代表共享资源)和一个FIFO
线程等待队列(CLH的变种,双向链表,多线程争用资源被阻塞时会进入此队列)。
这里volatile
能够保证多线程下的可见性,当state=1
则代表当前对象锁已经被占有,其他线程来加锁时则会失败,加锁失败的线程会被放入一个FIFO
的等待队列中,比列会被UNSAFE.park()
操作挂起,等待其他获取锁的线程释放锁才能够被唤醒。
另外state
的操作都是通过CAS
来保证其并发修改的安全性。
3、具体实现-ReentrantLock
调用Lock方法时,默认为非公平锁,构建公平锁需调用有参构造,true-公平锁,flase-非公平锁。
//lock方法
public void lock() {
sync.lock();
}
//默认无参构造,非公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
//有参构造
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
非公平锁加锁时:
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
//1、先通过CAS自旋尝试加锁,不判断当前等待队列是否有值
if (compareAndSetState(0, 1))
//2、获取锁成功,将当前线程设置为独占线程exclusiveOwnerThread
setExclusiveOwnerThread(Thread.currentThread());
else
//3、获取锁失败,再次尝试获取,失败则进入等待队列
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
public final void acquire(int arg) {
//先尝试获取锁,加锁失败尝试入队
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
//获取当前锁的标志,0表示没有线程获取锁,1表示有线程获取锁,大于1表示重入
int c = getState();
//锁空闲
if (c == 0) {
//再次通过CAS自选尝试获取锁
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");
//更新锁次数,后续每次释放锁次数-1,直到为0才释放锁
setState(nextc);
return true;
}
return false;
}
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
//判断当前节点的前置节点是否为head,是则再次尝试获取锁
if (p == head && tryAcquire(arg)) {
setHead(node);
//空置之前的head节点,方便gc回收
p.next = null; // help GC
failed = false;
return interrupted;
}
//尝试将当前节点waitStatus更新为SIGNAL,调用UNSAFE.park挂起当前线程
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
释放锁时:
public final boolean release(int arg) {
//尝试释放锁,可能成功释放,可能锁定次数-1(有重入)
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;
//本次释放锁后状态为0,则清空独占线程,不为0则表示还有锁定次数
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
private void unparkSuccessor(Node node) {
/*
* waitStatus-值说明:
* CANCELLED = 1 该节点由于超时或中断被取消
* SIGNAL = -1 信号量,表示此节点的后续节点已经或即将被阻塞
* CONDITION = -2 此节点当前位于条件队列,不会用作同步队列节点
* PROPAGATE = -3 表示应传播到其他节点
*/
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
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);
}
公平锁与非公平锁的实现区别:
公平锁在获取锁时会先判断队列里是否有排队的,且排队的不是当前线程。 非公平锁先通过CAS尝试获取锁,如获取失败则尝试入队判断当前节点的前置节点是否为head,如果为head则再次尝试获取锁,不是则更新节点状态,挂起当前节点线程!
//核心加锁代码
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;
}