前言
所谓的AQS(AbstractQueuedSynchronizer)提供了一套实现锁同步机制的框架,内部定义了很多锁相关的方法,JDK提供的大多数的同步器如ReentrantLock、ReentrantReadWriteLock、CountDownLatch、Semaphore等都是基于AQS来实现的。
- 一般是通过一个内部类Sync继承 AQS
- 将同步器所有调用都映射到Sync对应的方法
AQS核心结构
AQS内部维护属性volatile int state
- state表示同步状态
State三种访问方式:
- getState()
- setState()
- compareAndSetState()
定义了两种资源访问方式:
- Exclusive-独占,只有一个线程能执行,如ReentrantLock
- Share-共享,多个线程可以同时执行,如Semaphore/CountDownLatch
AQS实现时主要实现以下几种方法:
- isHeldExclusively():该线程是否正在独占资源。只有用到condition才需要去实现它。
- tryAcquire(int):独占方式。尝试获取资源,成功则返回true,失败则返回false。
- tryRelease(int):独占方式。尝试释放资源,成功则返回true,失败则返回false。
- tryAcquireShared(int):共享方式。尝试获取资源。负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。
- tryReleaseShared(int):共享方式。尝试释放资源,如果释放后允许唤醒后续等待结点返回true,否则返回false。
AQS定义两种队列
同步等待队列
作用: 主要用于维护获取锁失败时入队的线程。
AQS定义了两个指针:head和tail分别指向同步等待队列的头和尾,同时同步等待队列是一个双向链表结构,每个节点都有前驱节点(prev)和后继节点(next)
/**
* Head of the wait queue, lazily initialized.
*/
private transient volatile Node head;
/**
* Tail of the wait queue. After initialization, modified only via casTail.
*/
private transient volatile Node tail;
abstract static class Node {
volatile Node prev; // initially attached via casTail
volatile Node next; // visibly nonnull when signallable
Thread waiter; // visibly nonnull when enqueued
volatile int status; // written by owner, atomic bit ops by others
.......
}
用getQueuedThreads方法可以获得同步等待队列,从for循环可以看出获得的同步等待队列是从尾节点开始的列表
/**
* Returns a collection containing threads that may be waiting to
* acquire. Because the actual set of threads may change
* dynamically while constructing this result, the returned
* collection is only a best-effort estimate. The elements of the
* returned collection are in no particular order. This method is
* designed to facilitate construction of subclasses that provide
* more extensive monitoring facilities.
*
* @return the collection of threads
*/
public final Collection<Thread> getQueuedThreads() {
ArrayList<Thread> list = new ArrayList<>();
for (Node p = tail; p != null; p = p.prev) {
Thread t = p.waiter;
if (t != null)
list.add(t);
}
return list;
}
条件等待队列
作用: 调用await()的时候会释放锁,然后线程会加入到条件队列,调用signal()唤醒的时候会把条件队列中的线程节点移动到同步队列中,等待再次获得锁
AQS内部定义了一个ConditionObject内部类,内部类里面同样定义了两个指针:firstWaiter和lastWaiter分别指向条件等待队列的头和尾,但是条件等待队列是一个单向链表,nextWaiter来连接。
static final class ConditionNode extends Node implements ForkJoinPool.ManagedBlocker {}
public class ConditionObject implements Condition, java.io.Serializable {
private static final long serialVersionUID = 1173984872572414699L;
/** First node of condition queue. */
private transient ConditionNode firstWaiter;
/** Last node of condition queue. */
private transient ConditionNode lastWaiter;
.......
}
同样可以使用condition.getWaitingThreads()获得condition的条件等待队列,该队列是从第一个等待的线程开始的
/**
* Returns a collection containing those threads that may be
* waiting on this Condition.
* Implements {@link AbstractQueuedSynchronizer#getWaitingThreads(ConditionObject)}.
*
* @return the collection of threads
* @throws IllegalMonitorStateException if {@link #isHeldExclusively}
* returns {@code false}
*/
protected final Collection<Thread> getWaitingThreads() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
ArrayList<Thread> list = new ArrayList<>();
for (ConditionNode w = firstWaiter; w != null; w = w.nextWaiter) {
if ((w.status & COND) != 0) {
Thread t = w.waiter;
if (t != null)
list.add(t);
}
}
return list;
}