目录
AbstractQueuedSynchronizer又称为队列同步器(后面简称AQS)。
AQS的核心思想是,如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并将共享资源设置为锁定状态,如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制AQS是用CLH队列锁实现的,即将暂时获取不到锁的线程加入到队列中。
CLH(Craig,Landin,and Hagersten)队列是一个虚拟的双向队列,虚拟的双向队列即不存在队列实例,仅存在节点之间的关联关系。
AQS是将每一条请求共享资源的线程封装成一个CLH锁队列的一个结点(Node),来实现锁的分配。
AQS是一个抽象类。它是用来构建锁或其他同步组件的基础框架。查看继承关系
由上图可以看出。ReentrantLock、ReentrantReadWriteLock、Semaphore、以及线程池的工作线程也用的AQS的实现。
AQS是一个典型的是利用模板方法设计模式设计的一个工具。利用抽象类将公共实现的部分在抽象类的实现。具体的获取锁,释放锁的操作由各子类去实现、例如ReentrantLock和Semaphore。
1、介绍下AQS几个重要的组件
1.1 AQS内部成员变量state. 利用CAS原子操作,操作该变量,当state=0的时候 即没有线程去竞争共享资源,如果state>=1(支持锁可重入性 所以state>=1)说明共享资源已经被占用。
1.2 同步队列,同一个时间只会有一个线程去操作共享资源,其他未竞争到的线程就进入维护到一个同步队列,该队列由NODE节点维护,在后面我在详细的介绍
1.3 等待队列 condition 如果上述的同步队列的线程是等待的(有序或者无序即公平锁和非公平锁的实现)去获取锁,那么等待队列便是通过await和single等待和唤醒功能去加入到同步队列去获取锁。如果一直在等待队列不被唤醒。那么一直不会获取到锁之前。
2、内部成员变量state
所有的线程都去获取和释放state的值达到资源锁的效果
/**
* The synchronization state.
*/
// volatile 保证所有的线程可见
private volatile int state;
//获取内存中最新的是state值
protected final int getState() {
return state;
}
//set state的值
protected final void setState(int newState) {
state = newState;
}
// 通过原子操作CAS去更新state的值
protected final boolean compareAndSetState(int expect, int update) {
// See below for intrinsics setup to support this
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
3. 同步队列NODE
同步队列NODE是AQS的一个内部类
static final class Node {
CyclicBarrier
/** 标记是否共享模式 */
static final Node SHARED = new Node();
/** 标记是否独占模式 */
static final Node EXCLUSIVE = null;
//waitStatus 节点的状态值
static final int CANCELLED = 1;
static final int SIGNAL = -1;
static final int CONDITION = -2;
static final int PROPAGATE = -3;
volatile int waitStatus;
// 该节点的前置节点
volatile Node prev;
// 该节点的后置节点
volatile Node next;
//线程信息
volatile Thread thread;
//下一个等待节点
Node nextWaiter;
final boolean isShared() {
return nextWaiter == SHARED;
}
//返回当前节点的前置节点
final Node predecessor() throws NullPointerException {
Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
Node() { // Used to establish initial head or SHARED marker
}
Node(Thread thread, Node mode) { // Used by addWaiter
this.nextWaiter = mode;
this.thread = thread;
}
Node(Thread thread, int waitStatus) { // Used by Condition
this.waitStatus = waitStatus;
this.thread = thread;
}
}
模式
1.Exclusive:独占,只有一个线程能执行,如ReentrantLock
2.Share:共享,多个线程可以同时执行,如Semaphore、CountDownLatch、ReadWriteLock,
waitStatus:
1.CANCELLED
由于超时或中断,该节点被取消。
节点永远不会离开这个状态。特别是,
取消节点的线程不再阻塞。
2.SIGNAL 等待触发状态,前节点可能是head或者前节点为取消状态CANCELLED
3.CONDITION 与Condition相关,该标识的结点处于等待队列中,结点的线程等待在Condition上,当其他线程调用了Condition的signal()方法后,CONDITION状态的结点将从等待队列转移到同步队列中,等待获取同步锁。
4.PROPAGATE 与共享模式相关,在共享模式中,该状态标识结点的线程处于可运行状态。
4、等待队列 condition
ConditionObject 是AQS的内部类 ConditionObject就是实现的condition接口
需要注意的是。只有获取到锁的线程才可能是condition状态 另外只有在独占模式下才会有condition 相当于线程通信工具 与隐形锁syn的wait和notify是一个意思、
调用await需要去释放当前锁。
public class ConditionObject implements Condition, java.io.Serializable {
private static final long serialVersionUID = 1173984872572414699L;
/** First node of condition queue. */
private transient Node firstWaiter;
/** Last node of condition queue. */
private transient Node lastWaiter;
public ConditionObject() { }
private Node addConditionWaiter() {
Node t = lastWaiter;
// If lastWaiter is cancelled, clean out.
if (t != null && t.waitStatus != Node.CONDITION) {
unlinkCancelledWaiters();
t = lastWaiter;
}
Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null)
firstWaiter = node;
else
t.nextWaiter = node;
lastWaiter = node;
return node;
}
/**
* Removes and transfers nodes until hit non-cancelled one or
* null. Split out from signal in part to encourage compilers
* to inline the case of no waiters.
* @param first (non-null) the first node on condition queue
*/
private void doSignal(Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
/**
* Removes and transfers all nodes.
* @param first (non-null) the first node on condition queue
*/
private void doSignalAll(Node first) {
lastWaiter = firstWaiter = null;
do {
Node next = first.nextWaiter;
first.nextWaiter = null;
transferForSignal(first);
first = next;
} while (first != null);
}
/**
* Unlinks cancelled waiter nodes from condition queue.
* Called only while holding lock. This is called when
* cancellation occurred during condition wait, and upon
* insertion of a new waiter when lastWaiter is seen to have
* been cancelled. This method is needed to avoid garbage
* retention in the absence of signals. So even though it may
* require a full traversal, it comes into play only when
* timeouts or cancellations occur in the absence of
* signals. It traverses all nodes rather than stopping at a
* particular target to unlink all pointers to garbage nodes
* without requiring many re-traversals during cancellation
* storms.
*/
private void unlinkCancelledWaiters() {
Node t = firstWaiter;
Node trail = null;
while (t != null) {
Node next = t.nextWaiter;
if (t.waitStatus != Node.CONDITION) {
t.nextWaiter = null;
if (trail == null)
firstWaiter = next;
else
trail.nextWaiter = next;
if (next == null)
lastWaiter = trail;
}
else
trail = t;
t = next;
}
}
// public methods
/**
* Moves the longest-waiting thread, if one exists, from the
* wait queue for this condition to the wait queue for the
* owning lock.
*
* @throws IllegalMonitorStateException if {@link #isHeldExclusively}
* returns {@code false}
*/
public final void signal() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
/**
* Moves all threads from the wait queue for this condition to
* the wait queue for the owning lock.
*
* @throws IllegalMonitorStateException if {@link #isHeldExclusively}
* returns {@code false}
*/
public final void signalAll() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignalAll(first);
}
/**
* Implements uninterruptible condition wait.
* <ol>
* <li> Save lock state returned by {@link #getState}.
* <li> Invoke {@link #release} with saved state as argument,
* throwing IllegalMonitorStateException if it fails.
* <li> Block until signalled.
* <li> Reacquire by invoking specialized version of
* {@link #acquire} with saved state as argument.
* </ol>
*/
public final void awaitUninterruptibly() {
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
boolean interrupted = false;
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if (Thread.interrupted())
interrupted = true;
}
if (acquireQueued(node, savedState) || interrupted)
selfInterrupt();
}
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
long savedState = fullyRelease(node);
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
参考博客:
https://blog.csdn.net/javazejian/article/details/75043422
https://blog.csdn.net/mulinsen77/article/details/84583716