一、背景:
1 concurrent包的整体实现图如下图所示
2 AQS(java.util.concurrent.locks.AbstractQueuedSynchronizer)同步队列,它提供了一个基于FIFO队列,构建锁或者其他同步组件(信号量、事件等)的基础框架类。JDK中很多工具类的实现都是依赖于AQS,如ReentrantLock, Semaphore, CountDownLatch等等。
3 AQS的模板方法设计模式:
AQS的设计是使用模板方法设计模式,它将一些方法开放给子类进行重写,而同步器给同步组件所提供模板方法又会重新调用被子类所重写的方法。
AQS提供的模板方法可以分为3类:
独占式获取与释放同步状态;
共享式获取与释放同步状态;
查询同步队列中等待线程情况;
4 AQS可重写的方法:
5 在实现同步组件时AQS提供的模板方法:
- void acquire(int arg):获取独占锁。会调用tryAcquire方法,如果未获取成功,则会进入同步队列等待
- void acquireInterruptibly(int arg):响应中断版本的acquire
- boolean tryAcquireNanos(int arg,long nanos):响应中断+带超时版本的acquire
- void acquireShared(int arg):获取共享锁。会调用tryAcquireShared方法
- void acquireSharedInterruptibly(int arg):响应中断版本的acquireShared
- boolean tryAcquireSharedNanos(int arg,long nanos):响应中断+带超时版本的acquireShared
- boolean release(int arg):释放独占锁
- boolean releaseShared(int arg):释放共享锁
- Collection getQueuedThreads():获取同步队列上的线程集合
二 实现:
线程会首先尝试获取锁,如果失败,则将当前线程以及等待状态等信息包成一个Node节点加到同步队列里。
接着会不断循环尝试获取锁(条件是当前节点为head的直接后继才会尝试),如果失败则会阻塞自己,直至被唤醒;
而当持有锁的线程释放锁时,会唤醒队列中的后继线程。
三 应用:
- ReentrantLock: 使用了AQS的独占获取和释放,用state变量记录某个线程获取独占锁的次数,获取锁时+1,释放锁时-1,在获取时会校验线程是否可以获取锁。
- Semaphore: 使用了AQS的共享获取和释放,用state变量作为计数器,只有在大于0时允许线程进入。获取锁时-1,释放锁时+1。
- CountDownLatch: 使用了AQS的共享获取和释放,用state变量作为计数器,在初始化时指定。只要state还大于0,获取共享锁会因为失败而阻塞,直到计数器的值为0时,共享锁才允许获取,所有等待线程会被逐一唤醒。
四 数据结构:双向队列
五 AbstractQueuedSynchronizer类的源码分析
1 类的继承
public abstract class AbstractQueuedSynchronizer
extends AbstractOwnableSynchronizer
implements java.io.Serializable
AbstractQueuedSynchronizer继承自AbstractOwnableSynchronizer抽象类,并且实现了Serializable接口,可以进行序列化。
AbstractOwnableSynchronizer抽象类的源码如下:
public abstract class AbstractOwnableSynchronizer
implements java.io.Serializable {
// 版本序列号
private static final long serialVersionUID = 3737899427754241961L;
// 构造函数
protected AbstractOwnableSynchronizer() { }
// 独占模式下的线程
private transient Thread exclusiveOwnerThread;
// 设置独占线程
protected final void setExclusiveOwnerThread(Thread thread) {
exclusiveOwnerThread = thread;
}
// 获取独占线程
protected final Thread getExclusiveOwnerThread() {
return exclusiveOwnerThread;
}
}
2 类的内部类
AbstractQueuedSynchronizer类有两个内部类,分别为Node类与ConditionObject类
2.1 Node类
static final class Node {
// 模式,分为共享与独占
// 共享模式
static final Node SHARED = new Node();
// 独占模式
static final Node EXCLUSIVE = null;
// 结点状态
// CANCELLED,值为1,表示当前的线程被取消
// SIGNAL,值为-1,表示当前节点的后继节点包含的线程需要运行,也就是unpark
// CONDITION,值为-2,表示当前节点在等待condition,也就是在condition队列中
// PROPAGATE,值为-3,表示当前场景下后续的acquireShared能够得以执行
// 值为0,表示当前节点在sync队列中,等待着获取锁
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;
}
}
每个线程被阻塞的线程都会被封装成一个Node结点,放入队列。每个节点包含了一个Thread类型的引用,并且每个节点都存在一个状态,具体状态如下
① CANCELLED,值为1,表示当前的线程被取消。
② SIGNAL,值为-1,表示当前节点的后继节点包含的线程需要运行,需要进行unpark操作。
③ CONDITION,值为-2,表示当前节点在等待condition,也就是在condition queue中。
④ PROPAGATE,值为-3,表示当前场景下后续的acquireShared能够得以执行。
⑤ 值为0,表示当前节点在sync queue中,等待着获取锁。
2.2 ConditionObject类
// 内部类
public class ConditionObject implements Condition, java.io.Serializable {
// 版本号
private static final long serialVersionUID = 1173984872572414699L;
/** First node of condition queue. */
// condition队列的头结点
private transient Node firstWaiter;
/** Last node of condition queue. */
// condition队列的尾结点
private transient Node lastWaiter;
/**
* Creates a new {@code ConditionObject} instance.
*/
// 构造函数
public ConditionObject() { }
// Internal methods
/**
* Adds a new waiter to wait queue.
* @return its new wait node
*/
// 添加新的waiter到wait队列
private Node addConditionWaiter() {
// 保存尾结点
Node t = lastWaiter;
// If lastWaiter is cancelled, clean out.
if (t != null && t.waitStatus != Node.CONDITION) { // 尾结点不为空,并且尾结点的状态不为CONDITION
// 清除状态为CONDITION的结点
unlinkCancelledWaiters();
// 将最后一个结点重新赋值给t
t = lastWaiter;
}
// 新建一个结点
Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null) // 尾结点为空
// 设置condition队列的头结点
firstWaiter = node;
else // 尾结点不为空
// 设置为节点的nextWaiter域为node结点
t.nextWaiter = node;
// 更新condition队列的尾结点
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) // 该节点的nextWaiter为空
// 设置尾结点为空
lastWaiter = null;
// 设置first结点的nextWaiter域
first.nextWaiter = null;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null); // 将结点从condition队列转移到sync队列失败并且condition队列中的头结点不为空,一直循环
}
/**
* Removes and transfers all nodes.
* @param first (non-null) the first node on condition queue
*/
private void doSignalAll(Node first) {
// condition队列的头结点尾结点都设置为空
lastWaiter = firstWaiter = null;
// 循环
do {
// 获取first结点的nextWaiter域结点
Node next = first.nextWaiter;
// 设置first结点的nextWaiter域为空
first.nextWaiter = null;
// 将first结点从condition队列转移到sync队列
transferForSignal(first);
// 重新设置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.
*/
// 从condition队列中清除状态为CANCEL的结点
private void unlinkCancelledWaiters() {
// 保存condition队列头结点
Node t = firstWaiter;
Node trail = null;
while (t != null) { // t不为空
// 下一个结点
Node next = t.nextWaiter;
if (t.waitStatus != Node.CONDITION) { // t结点的状态不为CONDTION状态
// 设置t节点的额nextWaiter域为空
t.nextWaiter = null;
if (trail == null) // trail为空
// 重新设置condition队列的头结点
firstWaiter = next;
else // trail不为空
// 设置trail结点的nextWaiter域为next结点
trail.nextWaiter = next;
if (next == null) // next结点为空
// 设置condition队列的尾结点
lastWaiter = trail;
}
else // t结点的状态为CONDTION状态
// 设置trail结点
trail = t;
// 设置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}
*/
// 唤醒一个等待线程。如果所有的线程都在等待此条件,则选择其中的一个唤醒。在从 await 返回之前,该线程必须重新获取锁。
public final void signal() {
if (!isHeldExclusively()) // 不被当前线程独占,抛出异常
throw new IllegalMonitorStateException();
// 保存condition队列头结点
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}
*/
// 唤醒所有等待线程。如果所有的线程都在等待此条件,则唤醒所有线程。在从 await 返回之前,每个线程都必须重新获取锁。
public final void signalAll() {
if (!isHeldExclusively()) // 不被当前线程独占,抛出异常
throw new IllegalMonitorStateException();
// 保存condition队列头结点
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状态
interrupted = true;
}
if (acquireQueued(node, savedState) || interrupted) //
selfInterrupt();
}
/*
* For interruptible waits, we need to track whether to throw
* InterruptedException, if interrupted while blocked on
* condition, versus reinterrupt current thread, if
* interrupted while blocked waiting to re-acquire.
*/
/** Mode meaning to reinterrupt on exit from wait */
private static final int REINTERRUPT = 1;
/** Mode meaning to throw InterruptedException on exit from wait */
private static final int THROW_IE = -1;
/**
* Checks for interrupt, returning THROW_IE if interrupted
* before signalled, REINTERRUPT if after signalled, or
* 0 if not interrupted.
*/
private int checkInterruptWhileWaiting(Node node) {
return Thread.interrupted() ?
(transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
0;
}
/**
* Throws InterruptedException, reinterrupts current thread, or
* does nothing, depending on mode.
*/
private void reportInterruptAfterWait(int interruptMode)
throws InterruptedException {
if (interruptMode == THROW_IE)
throw new InterruptedException();
else if (interruptMode == REINTERRUPT)
selfInterrupt();
}
/**
* Implements interruptible condition wait.
* <ol>
* <li> If current thread is interrupted, throw InterruptedException.
* <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 or interrupted.
* <li> Reacquire by invoking specialized version of
* {@link #acquire} with saved state as argument.
* <li> If interrupted while blocked in step 4, throw InterruptedException.
* </ol>
*/
// // 等待,当前线程在接到信号或被中断之前一直处于等待状态
public final void await() throws InterruptedException {
if (Thread.interrupted()) // 当前线程被中断,抛出异常
throw new InterruptedException();
// 在wait队列上添加一个结点
Node node = addConditionWaiter();
//
int 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);
}
/**
* Implements timed condition wait.
* <ol>
* <li> If current thread is interrupted, throw InterruptedException.
* <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, interrupted, or timed out.
* <li> Reacquire by invoking specialized version of
* {@link #acquire} with saved state as argument.
* <li> If interrupted while blocked in step 4, throw InterruptedException.
* </ol>
*/
// 等待,当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态
public final long awaitNanos(long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
final long deadline = System.nanoTime() + nanosTimeout;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
if (nanosTimeout <= 0L) {
transferAfterCancelledWait(node);
break;
}
if (nanosTimeout >= spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
nanosTimeout = deadline - System.nanoTime();
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
return deadline - System.nanoTime();
}
/**
* Implements absolute timed condition wait.
* <ol>
* <li> If current thread is interrupted, throw InterruptedException.
* <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, interrupted, or timed out.
* <li> Reacquire by invoking specialized version of
* {@link #acquire} with saved state as argument.
* <li> If interrupted while blocked in step 4, throw InterruptedException.
* <li> If timed out while blocked in step 4, return false, else true.
* </ol>
*/
// 等待,当前线程在接到信号、被中断或到达指定最后期限之前一直处于等待状态
public final boolean awaitUntil(Date deadline)
throws InterruptedException {
long abstime = deadline.getTime();
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
boolean timedout = false;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
if (System.currentTimeMillis() > abstime) {
timedout = transferAfterCancelledWait(node);
break;
}
LockSupport.parkUntil(this, abstime);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
return !timedout;
}
/**
* Implements timed condition wait.
* <ol>
* <li> If current thread is interrupted, throw InterruptedException.
* <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, interrupted, or timed out.
* <li> Reacquire by invoking specialized version of
* {@link #acquire} with saved state as argument.
* <li> If interrupted while blocked in step 4, throw InterruptedException.
* <li> If timed out while blocked in step 4, return false, else true.
* </ol>
*/
// 等待,当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。此方法在行为上等效于:awaitNanos(unit.toNanos(time)) > 0
public final boolean await(long time, TimeUnit unit)
throws InterruptedException {
long nanosTimeout = unit.toNanos(time);
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
final long deadline = System.nanoTime() + nanosTimeout;
boolean timedout = false;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
if (nanosTimeout <= 0L) {
timedout = transferAfterCancelledWait(node);
break;
}
if (nanosTimeout >= spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
nanosTimeout = deadline - System.nanoTime();
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
return !timedout;
}
// support for instrumentation
/**
* Returns true if this condition was created by the given
* synchronization object.
*
* @return {@code true} if owned
*/
final boolean isOwnedBy(AbstractQueuedSynchronizer sync) {
return sync == AbstractQueuedSynchronizer.this;
}
/**
* Queries whether any threads are waiting on this condition.
* Implements {@link AbstractQueuedSynchronizer#hasWaiters(ConditionObject)}.
*
* @return {@code true} if there are any waiting threads
* @throws IllegalMonitorStateException if {@link #isHeldExclusively}
* returns {@code false}
*/
// 查询是否有正在等待此条件的任何线程
protected final boolean hasWaiters() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
if (w.waitStatus == Node.CONDITION)
return true;
}
return false;
}
/**
* Returns an estimate of the number of threads waiting on
* this condition.
* Implements {@link AbstractQueuedSynchronizer#getWaitQueueLength(ConditionObject)}.
*
* @return the estimated number of waiting threads
* @throws IllegalMonitorStateException if {@link #isHeldExclusively}
* returns {@code false}
*/
// 返回正在等待此条件的线程数估计值
protected final int getWaitQueueLength() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
int n = 0;
for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
if (w.waitStatus == Node.CONDITION)
++n;
}
return n;
}
/**
* 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<Thread>();
for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
if (w.waitStatus == Node.CONDITION) {
Thread t = w.thread;
if (t != null)
list.add(t);
}
}
return list;
}
}
此类实现了Condition接口,Condition接口定义了条件操作规范,具体如下:
public interface Condition {
// 等待,当前线程在接到信号或被中断之前一直处于等待状态
void await() throws InterruptedException;
// 等待,当前线程在接到信号之前一直处于等待状态,不响应中断
void awaitUninterruptibly();
//等待,当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态
long awaitNanos(long nanosTimeout) throws InterruptedException;
// 等待,当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。此方法在行为上等效于:awaitNanos(unit.toNanos(time)) > 0
boolean await(long time, TimeUnit unit) throws InterruptedException;
// 等待,当前线程在接到信号、被中断或到达指定最后期限之前一直处于等待状态
boolean awaitUntil(Date deadline) throws InterruptedException;
// 唤醒一个等待线程。如果所有的线程都在等待此条件,则选择其中的一个唤醒。在从 await 返回之前,该线程必须重新获取锁。
void signal();
// 唤醒所有等待线程。如果所有的线程都在等待此条件,则唤醒所有线程。在从 await 返回之前,每个线程都必须重新获取锁。
void signalAll();
}
Condition接口中定义了await、signal函数,用来等待条件、释放条件。
2.3 类的属性
public abstract class AbstractQueuedSynchronizer
extends AbstractOwnableSynchronizer
implements java.io.Serializable {
// 版本号
private static final long serialVersionUID = 7373984972572414691L;
// 头结点
private transient volatile Node head;
// 尾结点
private transient volatile Node tail;
// 状态
private volatile int state;
// 自旋时间
static final long spinForTimeoutThreshold = 1000L;
// Unsafe类实例
private static final Unsafe unsafe = Unsafe.getUnsafe();
// state内存偏移地址
private static final long stateOffset;
// head内存偏移地址
private static final long headOffset;
// state内存偏移地址
private static final long tailOffset;
// tail内存偏移地址
private static final long waitStatusOffset;
// next内存偏移地址
private static final long nextOffset;
// 静态初始化块
static {
try {
stateOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("state"));
headOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("head"));
tailOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
waitStatusOffset = unsafe.objectFieldOffset
(Node.class.getDeclaredField("waitStatus"));
nextOffset = unsafe.objectFieldOffset
(Node.class.getDeclaredField("next"));
} catch (Exception ex) { throw new Error(ex); }
}
}
属性中包含了头结点head,尾结点tail,状态state、自旋时间spinForTimeoutThreshold,还有AbstractQueuedSynchronizer抽象的属性在内存中的偏移地址,通过该偏移地址,可以获取和设置该属性的值,同时还包括一个静态初始化块,用于加载内存偏移地址。
2.4 核心函数之独占锁
2.4.1 acquire函数:该函数以独占模式获取(资源),忽略中断,即线程在aquire过程中,中断此线程是无效的
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
说明:
① 首先调用tryAcquire函数,调用此方法的线程会试图在独占模式下获取对象状态。此方法应该查询是否允许它在独占模式下获取对象状态,如果允许,则获取它。在AbstractQueuedSynchronizer源码中默认会抛出一个异常,即需要子类去重写此函数完成自己的逻辑。
② 若tryAcquire失败,则调用addWaiter函数,addWaiter函数完成的功能是将调用此方法的线程封装成为一个结点并放入Sync queue。
③ 调用acquireQueued函数,此函数完成的功能是Sync queue中的结点不断尝试获取资源,若成功,则返回true,否则,返回false。
tryAcquire方法
// 尝试去获取独占锁,立即返回。如果返回true表示获取锁成功。
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
如果子类想实现独占锁,则必须重写这个方法,否则抛出异常。这个方法的作用是当前线程尝试获取锁,如果获取到锁,就会返回true,并更改锁资源。没有获取到锁返回false。
addWaiter函数:
// 添加等待者
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域连接到尾结点
node.prev = pred;
if (compareAndSetTail(pred, node)) { // 比较pred是否为尾结点,是则将尾结点设置为node
// 设置尾结点的next域为node
pred.next = node;
return node; // 返回新生成的结点
}
}
enq(node); // 尾结点为空(即还没有被初始化过),或者是compareAndSetTail操作失败,则入队列
return node;
}
addWaiter函数使用快速添加的方式往sync queue尾部添加结点,如果sync queue队列还没有初始化,则会使用enq插入队列中,enq方法源码如下:
// 入队列
private Node enq(final Node node) {
for (;;) { // 无限循环,确保结点能够成功入队列
// 保存尾结点
Node t = tail;
if (t == null) { // 尾结点为空,即还没被初始化
if (compareAndSetHead(new Node())) // 头结点为空,并设置头结点为新生成的结点
tail = head; // 头结点与尾结点都指向同一个新生结点
} else { // 尾结点不为空,即已经被初始化过
// 将node结点的prev域连接到尾结点
node.prev = t;
if (compareAndSetTail(t, node)) { // 比较结点t是否为尾结点,若是则将尾结点设置为node
// 设置尾结点的next域为node
t.next = node;
return t; // 返回尾结点
}
}
}
}
enq函数会使用无限循环来确保节点的成功插入。
acquireQueue函数作用就是获取锁,如果没有获取到,就让当前线程阻塞等待。
/**
* 想要获取锁的 acquire系列方法,都会这个方法来获取锁
* 循环通过tryAcquire方法不断去获取锁,如果没有获取成功,
* 就有可能调用parkAndCheckInterrupt方法,让当前线程阻塞
* @param node 想要获取锁的节点
* @param arg
* @return 返回true,表示在线程等待的过程中,线程被中断了
*/
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
// 表示线程在等待过程中,是否被中断了
boolean interrupted = false;
// 通过死循环,直到node节点的线程获取到锁,才返回
for (;;) {
// 获取node的前一个节点
final Node p = node.predecessor();
// 如果前一个节点是队列头head,并且尝试获取锁成功
// 那么当前线程就不需要阻塞等待,继续执行
if (p == head && tryAcquire(arg)) {
// 将节点node设置为新的队列头
setHead(node);
// help GC
p.next = null;
// 不需要调用cancelAcquire方法
failed = false;
return interrupted;
}
// 当p节点的状态是Node.SIGNAL时,就会调用parkAndCheckInterrupt方法,阻塞node线程
// node线程被阻塞,有两种方式唤醒,
// 1.是在unparkSuccessor(Node node)方法,会唤醒被阻塞的node线程,返回false
// 2.node线程被调用了interrupt方法,线程被唤醒,返回true
// 在这里只是简单地将interrupted = true,没有跳出for的死循环,继续尝试获取锁
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
// failed为true,表示发生异常,非正常退出
// 则将node节点的状态设置成CANCELLED,表示node节点所在线程已取消,不需要唤醒了。
if (failed)
cancelAcquire(node);
}
}
首先获取当前节点的前驱节点,如果前驱节点是头结点并且能够获取(资源),代表该当前节点能够占有锁,设置头结点为当前节点,返回。否则,调用shouldParkAfterFailedAcquire和parkAndCheckInterrupt函数
shouldParkAfterFailedAcquire函数:
/**
* 根据前一个节点pred的状态,来判断当前线程是否应该被阻塞
* @param pred : node节点的前一个节点
* @param node
* @return 返回true 表示当前线程应该被阻塞,之后应该会调用parkAndCheckInterrupt方法来阻塞当前线程
*/
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
// 如果前一个pred的状态是Node.SIGNAL,那么直接返回true,当前线程应该被阻塞
return true;
if (ws > 0) {
// 如果前一个节点状态是Node.CANCELLED(大于0就是CANCELLED),
// 表示前一个节点所在线程已经被唤醒了,要从CLH队列中移除CANCELLED的节点。
// 所以从pred节点一直向前查找直到找到不是CANCELLED状态的节点,并把它赋值给node.prev,
// 表示node节点的前一个节点已经改变。
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
// 此时前一个节点pred的状态只能是0或者PROPAGATE,不可能是CONDITION状态
// CONDITION(这个是特殊状态,只在condition列表中节点中存在,CLH队列中不存在这个状态的节点)
// 将前一个节点pred的状态设置成Node.SIGNAL,这样在下一次循环时,就是直接阻塞当前线程
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
如果前一个节点状态是Node.SIGNAL,那么直接返回true,阻塞当前线程
如果前一个节点状态是Node.CANCELLED(大于0就是CANCELLED),表示前一个节点所在线程已经被唤醒了,要从CLH队列中移除CANCELLED的节点。所以从pred节点一直向前查找直到找到不是CANCELLED状态的节点。
并把它赋值给node.prev,表示node节点的前一个节点已经改变。在acquireQueued方法中进行下一次循环。
不是前面两种状态,那么就将前一个节点状态设置成Node.SIGNAL,表示需要阻塞当前线程,这样再下一次循环时,就会直接阻塞当前线程。
parkAndCheckInterrupt函数:阻塞当前线程,线程被唤醒后返回当前线程中断状态
/**
* 阻塞当前线程,线程被唤醒后返回当前线程中断状态
*/
private final boolean parkAndCheckInterrupt() {
// 通过LockSupport.park方法,阻塞当前线程
LockSupport.park(this);
// 当前线程被唤醒后,返回当前线程中断状态
return Thread.interrupted();
}
函数里的逻辑是首先执行park操作,即禁用当前线程,然后返回该线程是否已经被中断
cancelAcquire函数:将node节点的状态设置成CANCELLED,表示node节点所在线程已取消,不需要唤醒了。
// 取消继续获取(资源)
private void cancelAcquire(Node node) {
// Ignore if node doesn't exist
// node为空,返回
if (node == null)
return;
// 设置node结点的thread为空
node.thread = null;
// Skip cancelled predecessors
// 保存node的前驱结点
Node pred = node.prev;
while (pred.waitStatus > 0) // 找到node前驱结点中第一个状态小于0的结点,即不为CANCELLED状态的结点
node.prev = pred = pred.prev;
// predNext is the apparent node to unsplice. CASes below will
// fail if not, in which case, we lost race vs another cancel
// or signal, so no further action is necessary.
// 获取pred结点的下一个结点
Node predNext = pred.next;
// Can use unconditional write instead of CAS here.
// After this atomic step, other Nodes can skip past us.
// Before, we are free of interference from other threads.
// 设置node结点的状态为CANCELLED
node.waitStatus = Node.CANCELLED;
// If we are the tail, remove ourselves.
if (node == tail && compareAndSetTail(node, pred)) { // node结点为尾结点,则设置尾结点为pred结点
// 比较并设置pred结点的next节点为null
compareAndSetNext(pred, predNext, null);
} else { // node结点不为尾结点,或者比较设置不成功
// If successor needs signal, try to set pred's next-link
// so it will get one. Otherwise wake it up to propagate.
int ws;
if (pred != head &&
((ws = pred.waitStatus) == Node.SIGNAL ||
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
pred.thread != null) { // (pred结点不为头结点,并且pred结点的状态为SIGNAL)或者
// pred结点状态小于等于0,并且比较并设置等待状态为SIGNAL成功,并且pred结点所封装的线程不为空
// 保存结点的后继
Node next = node.next;
if (next != null && next.waitStatus <= 0) // 后继不为空并且后继的状态小于等于0
compareAndSetNext(pred, predNext, next); // 比较并设置pred.next = next;
} else {
unparkSuccessor(node); // 释放node的前一个结点
}
node.next = node; // help GC
}
}
函数完成的功能就是取消当前线程对资源的获取,即设置该结点的状态为CANCELLED
unparkSuccessor函数:唤醒node节点的下一个非取消状态的节点所在线程
// 唤醒node节点的下一个非取消状态的节点所在线程(即waitStatus<=0)
private void unparkSuccessor(Node node) {
// 获取node节点的状态
int ws = node.waitStatus;
// 如果小于0,就将状态重新设置为0,表示这个node节点已经完成了
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
// 下一个节点
Node s = node.next;
// 如果下一个节点为null,或者状态是已取消,那么就要寻找下一个非取消状态的节点
if (s == null || s.waitStatus > 0) {
// 先将s设置为null,s不是非取消状态的节点
s = null;
// 从队列尾向前遍历,直到遍历到node节点
for (Node t = tail; t != null && t != node; t = t.prev)
// 因为是从后向前遍历,所以不断覆盖找到的值,这样才能得到node节点后下一个非取消状态的节点
if (t.waitStatus <= 0)
s = t;
}
// 如果s不为null,表示存在非取消状态的节点。那么调用LockSupport.unpark方法,唤醒这个节点的线程
if (s != null)
LockSupport.unpark(s.thread);
}
流程:
将node节点的状态设置为0
寻找到下一个非取消状态的节点s
如果节点s不为null,则调用LockSupport.unpark(s.thread)方法唤醒s所在线程。
release:以独占模式释放对象
// 在独占锁模式下,释放锁的操作
public final boolean release(int arg) {
// 调用tryRelease方法,尝试去释放锁,由子类具体实现
if (tryRelease(arg)) {
Node h = head;
// 如果队列头节点的状态不是0,那么队列中就可能存在需要唤醒的等待节点。
// 还记得我们在acquireQueued(final Node node, int arg)获取锁的方法中,如果节点node没有获取到锁,
// 那么我们会将节点node的前一个节点状态设置为Node.SIGNAL,然后调用parkAndCheckInterrupt方法
// 将节点node所在线程阻塞。
// 在这里就是通过unparkSuccessor方法,进而调用LockSupport.unpark(s.thread)方法,唤醒被阻塞的线程
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
tryRelease方法:
// 尝试去释放当前线程持有的独占锁,立即返回。如果返回true表示释放锁成功
protected boolean tryRelease(int arg) {
throw new UnsupportedOperationException();
}
子类想实现独占锁,则必须重写这个方法,否则抛出异常。作用是释放当前线程持有的锁,返回true表示已经完全释放锁资源,返回false,表示还持有锁资源
调用tryRelease方法去释放当前持有的锁资源。
如果完全释放了锁资源,那么就调用unparkSuccessor方法,去唤醒一个等待锁的线程。
2.5 核心函数之共享锁
2.5.1 acquireShared方法 :获取共享锁
acquireShared方法
// 获取共享锁
public final void acquireShared(int arg) {
// 尝试去获取共享锁,如果返回值小于0表示获取共享锁失败
if (tryAcquireShared(arg) < 0)
// 调用doAcquireShared方法去获取共享锁
doAcquireShared(arg);
}
调用tryAcquireShared方法尝试获取共享锁,如果返回值小于0表示获取共享锁失败.则继续调用doAcquireShared方法获取共享锁。
tryAcquireShared方法
// 尝试去获取共享锁,立即返回。返回值大于等于0,表示获取共享锁成功
protected int tryAcquireShared(int arg) {
throw new UnsupportedOperationException();
}
子类想实现共享锁,则必须重写这个方法,否则抛出异常。作用是尝试获取共享锁,返回值大于等于0,表示获取共享锁成功。
doAcquireShared方法
/**
* 获取共享锁,获取失败,则会阻塞当前线程,直到获取共享锁返回
* @param arg the acquire argument
*/
private void doAcquireShared(int arg) {
// 为当前线程创建共享锁节点node
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
// 如果节点node前一个节点是同步队列头节点。就会调用tryAcquireShared方法尝试获取共享锁
if (p == head) {
int r = tryAcquireShared(arg);
// 如果返回值大于0,表示获取共享锁成功
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
if (interrupted)
selfInterrupt();
failed = false;
return;
}
}
// 如果节点p的状态是Node.SIGNAL,就是调用parkAndCheckInterrupt方法阻塞当前线程
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
// failed为true,表示发生异常,
// 则将node节点的状态设置成CANCELLED,表示node节点所在线程已取消,不需要唤醒了
if (failed)
cancelAcquire(node);
}
}
这个方法与独占锁的acquireQueued方法相比较,不同如下:
1、doAcquireShared方法,调用addWaiter(Node.SHARED)方法,为当前线程创建一个共享模式的节点node。而acquireQueued方法是由外部传递来的。
2、doAcquireShared方法没有返回值,acquireQueued方法会返回布尔类型的值,是当前线程中断标志位值
3、重新设置CLH队列头的方法不一样。doAcquireShared方法调用setHeadAndPropagate方法,而acquireQueued方法调用setHead方法。
setHeadAndPropagate方法
// 重新设置CLH队列头,如果CLH队列头的下一个节点为null或者共享模式,
// 那么就要唤醒共享锁上等待的线程
private void setHeadAndPropagate(Node node, int propagate) {
Node h = head;
// 设置新的同步队列头head
setHead(node);
// 如果propagate大于0,
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
// 获取新的CLH队列头的下一个节点s
Node s = node.next;
// 如果节点s是空或者共享模式节点,那么就要唤醒共享锁上等待的线程
if (s == null || s.isShared())
doReleaseShared();
}
}
releaseShared方法:释放共享锁的方法
// 释放共享锁
public final boolean releaseShared(int arg) {
// 尝试释放共享锁
if (tryReleaseShared(arg)) {
// 唤醒等待共享锁的线程
doReleaseShared();
return true;
}
return false;
}
tryReleaseShared方法
// 尝试去释放共享锁
protected boolean tryReleaseShared(int arg) {
throw new UnsupportedOperationException();
}
子类想实现共享锁,则必须重写这个方法,否则抛出异常。作用是释放当前线程持有的锁,返回true表示已经完全释放锁资源,返回false,表示还持有锁资源。
doReleaseShared方法:
// 会唤醒等待共享锁的线程
private void doReleaseShared() {
for (;;) {
// 将同步队列头赋值给节点h
Node h = head;
// 如果节点h不为null,且不等于同步队列尾
if (h != null && h != tail) {
// 得到节点h的状态
int ws = h.waitStatus;
// 如果状态是Node.SIGNAL,就要唤醒节点h后继节点的线程
if (ws == Node.SIGNAL) {
// 将节点h的状态设置成0,如果设置失败,就继续循环,再试一次。
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
// 唤醒节点h后继节点的线程
unparkSuccessor(h);
}
// 如果节点h的状态是0,就设置ws的状态是PROPAGATE。
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
// 如果同步队列头head节点发生改变,继续循环,
// 如果没有改变,就跳出循环
if (h == head)
break;
}
}
2.6 核心函数之Condition
Condition实现了线程之间相互等待,并只能在独占锁中才能使用。
await方法:让当前持有锁的线程释放锁,并唤醒一个队列上等待锁的线程,再为当前线程创建一个node节点,插入到Condition队列
/**
* 让当前持有锁的线程阻塞等待,并释放锁。如果有中断请求,则抛出InterruptedException异常
* @throws InterruptedException
*/
public final void await() throws InterruptedException {
// 如果当前线程中断标志位是true,就抛出InterruptedException异常
if (Thread.interrupted())
throw new InterruptedException();
// 为当前线程创建新的Node节点,并且将这个节点插入到Condition队列中了
Node node = addConditionWaiter();
// 释放当前线程占有的锁,并唤醒CLH队列一个等待线程
int savedState = fullyRelease(node);
int interruptMode = 0;
// 如果节点node不在同步队列中(注意不是Condition队列)
while (!isOnSyncQueue(node)) {
// 阻塞当前线程,那么怎么唤醒这个线程呢?
// 首先我们必须调用signal或者signalAll将这个节点node加入到同步队列。
// 只有这样unparkSuccessor(Node node)方法,才有可能唤醒被阻塞的线程
LockSupport.park(this);
// 如果当前线程产生中断请求,就跳出循环
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
// 如果节点node已经在同步队列中了,获取同步锁,只有得到锁才能继续执行,否则线程继续阻塞等待
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
// 清除Condition队列中状态不是Node.CONDITION的节点
if (node.nextWaiter != null)
unlinkCancelledWaiters();
// 是否要抛出异常,或者发出中断请求
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
流程如下:
1、addConditionWaiter方法:为当前线程创建新的Node节点,并且将这个节点插入到Condition队列中了
2、fullyRelease方法:释放当前线程占有的锁,并唤醒CLH队列一个等待线程
3、isOnSyncQueue 方法:如果返回false,表示节点node不在CLH队列中,即没有调用过 signal系列方法,所以调用LockSupport.park(this)方法阻塞当前线程。
4、如果跳出while循环,表示节点node已经在CLH队列中,那么调用acquireQueued方法去获取锁。
5、清除Condition队列中状态不是Node.CONDITION的节点
addConditionWaiter方法:为当前线程创建新的Node节点,并且将这个节点插入到Condition队列中
private Node addConditionWaiter() {
Node t = lastWaiter;
// 如果Condition队列尾节点的状态不是Node.CONDITION
if (t != null && t.waitStatus != Node.CONDITION) {
// 清除Condition队列中,状态不是Node.CONDITION的节点,
// 并且可能会重新设置firstWaiter和lastWaiter
unlinkCancelledWaiters();
// 重新将Condition队列尾赋值给t
t = lastWaiter;
}
// 为当前线程创建一个状态为Node.CONDITION的节点
Node node = new Node(Thread.currentThread(), Node.CONDITION);
// 如果t为null,表示Condition队列为空,将node节点赋值给链表头
if (t == null)
firstWaiter = node;
else
// 将新节点node插入到Condition队列尾
t.nextWaiter = node;
// 将新节点node设置为新的Condition队列尾
lastWaiter = node;
return node;
}
fullyRelease方法:释放当前线程占有的锁,并唤醒CLH队列一个等待线程
/**
* 释放当前线程占有的锁,并唤醒CLH队列一个等待线程
* 如果失败就抛出异常,设置node节点的状态是Node.CANCELLED
* @return
*/
final int fullyRelease(Node node) {
boolean failed = true;
try {
int savedState = getState();
// 释放当前线程占有的锁
if (release(savedState)) {
failed = false;
return savedState;
} else {
throw new IllegalMonitorStateException();
}
} finally {
if (failed)
node.waitStatus = Node.CANCELLED;
}
}
isOnSyncQueue方法:节点node是不是在CLH队列中
// 节点node是不是在CLH队列中
final boolean isOnSyncQueue(Node node) {
// 如果node的状态是Node.CONDITION,或者node没有前一个节点prev,
// 那么返回false,节点node不在同步队列中
if (node.waitStatus == Node.CONDITION || node.prev == null)
return false;
// 如果node有下一个节点next,那么它一定在同步队列中
if (node.next != null) // If has successor, it must be on queue
return true;
// 从同步队列中查找节点node
return findNodeFromTail(node);
}
// 在同步队列中从后向前查找节点node,如果找到返回true,否则返回false
private boolean findNodeFromTail(Node node) {
Node t = tail;
for (;;) {
if (t == node)
return true;
if (t == null)
return false;
t = t.prev;
}
}
acquireQueued方法:获取独占锁
unlinkCancelledWaiters方法:清除Condition队列中状态不是Node.CONDITION的节点
private void unlinkCancelledWaiters() {
// condition队列头赋值给t
Node t = firstWaiter;
// 这个trail节点,只是起辅助作用
Node trail = null;
while (t != null) {
//得到下一个节点next。当节点是condition时候,nextWaiter表示condition队列的下一个节点
Node next = t.nextWaiter;
// 如果节点t的状态不是CONDITION,那么该节点就要从condition队列中移除
if (t.waitStatus != Node.CONDITION) {
// 将节点t的nextWaiter设置为null
t.nextWaiter = null;
// 如果trail为null,表示原先的condition队列头节点实效,需要设置新的condition队列头
if (trail == null)
firstWaiter = next;
else
// 将节点t从condition队列中移除,因为改变了引用的指向,从condition队列中已经找不到节点t了
trail.nextWaiter = next;
// 如果next为null,表示原先的condition队列尾节点也实效,重新设置队列尾节点
if (next == null)
lastWaiter = trail;
}
else
// 遍历到的有效节点
trail = t;
// 将next赋值给t,遍历完整个condition队列
t = next;
}
}
reportInterruptAfterWait方法:
/**
* 如果interruptMode是THROW_IE,就抛出InterruptedException异常
* 如果interruptMode是REINTERRUPT,则当前线程再发出中断请求
* 否则就什么都不做
*/
private void reportInterruptAfterWait(int interruptMode)
throws InterruptedException {
if (interruptMode == THROW_IE)
throw new InterruptedException();
else if (interruptMode == REINTERRUPT)
selfInterrupt();
}
signal方法:condition队列不为空,就调用doSignal方法将condition队列头节点插入到CLH队列中。
// 如果condition队列不为空,将condition队列头节点插入到同步队列中
public final void signal() {
// 如果当前线程不是独占锁线程,就抛出IllegalMonitorStateException异常
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
// 将Condition队列头赋值给节点first
Node first = firstWaiter;
if (first != null)
// 将Condition队列中的first节点插入到CLH队列中
doSignal(first);
}
doSignal方法:
// 将Condition队列中的first节点插入到CLH队列中
private void doSignal(Node first) {
do {
// 原先的Condition队列头节点取消,所以重新赋值Condition队列头节点
// 如果新的Condition队列头节点为null,表示Condition队列为空了
// ,所以也要设置Condition队列尾lastWaiter为null
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
// 取消first节点nextWaiter引用
first.nextWaiter = null;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
while循环,只有Node.CONDITION状态的节点才能插入CLH队列
transferForSignal方法:
// 返回true表示节点node插入到同步队列中,返回false表示节点node没有插入到同步队列中
final boolean transferForSignal(Node node) {
// 如果节点node的状态不是Node.CONDITION,或者更新状态失败,
// 说明该node节点已经插入到同步队列中,所以直接返回false
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
// 将节点node插入到同步队列中,p是原先同步队列尾节点,也是node节点的前一个节点
Node p = enq(node);
int ws = p.waitStatus;
// 如果前一个节点是已取消状态,或者不能将它设置成Node.SIGNAL状态。
// 就说明节点p之后也不会发起唤醒下一个node节点线程的操作,
// 所以这里直接调用 LockSupport.unpark(node.thread)方法,唤醒节点node所在线程
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread);
return true;
}
说明:
1、状态不是 Node.CONDITION的节点,是不能从Condition队列中插入到CLH队列中。直接返回false
2、调用enq方法,将节点node插入到同步队列中,p是原先同步队列尾节点,也是node节点的前一个节点
3、如果前一个节点是已取消状态,或者不能将它设置成Node.SIGNAL状态。那么就要LockSupport.unpark(node.thread)方法唤醒node节点所在线程。
signalAll 方法:
// 将condition队列中所有的节点都插入到同步队列中
public final void signalAll() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignalAll(first);
}
doSignalAll方法:
/**
* 将condition队列中所有的节点都插入到同步队列中
* @param first condition队列头节点
*/
private void doSignalAll(Node first) {
// 表示将condition队列设置为空
lastWaiter = firstWaiter = null;
do {
// 得到condition队列的下一个节点
Node next = first.nextWaiter;
first.nextWaiter = null;
// 将节点first插入到同步队列中
transferForSignal(first);
first = next;
// 循环遍历condition队列中所有的节点
} while (first != null);
}
循环遍历整个condition队列,调用transferForSignal方法,将节点插入到CLH队列中
总结:
AQS类来实现独占锁和共享锁:
1、内部有一个CLH队列,用来记录所有等待锁的线程
2、acquire系列方法用来获取独占锁,获取失败,则阻塞当前线程
3、release方法用来释放独占锁,释放成功,则会唤醒一个等待独占锁的线程。
4、acquireShared系列方法用来获取共享锁。
5、releaseShared方法用来释放共享锁。
6、Condition来实现线程之间相互等待的。