主要原因是在多线程的情况下,某个线程设置前置结点时使用的 tail 和设置后继结点时使用的 tail 可能并不是同一个,同时如果不使用局部变量记录 tail 结点,那么 CAS 操作也不能正常进行,因为每次使用的都是同一个tail。具体请看—— addWaiter问题
2、为什么只保证设置前置结点时的原子性?
从源码中可以看出来,每次 CAS 操作之前设置的是当前的结点的前置结点 node.prev,即保证了前置域设置的原子性。AQS 使用双向链表,双向链表目前没有无锁算法的实现。双向链表需要同时设置前驱和后继结点,这两次操作只能保证一个是原子性的。即不能同时保证前置域 prev 的原子性和后置域 next 的原子性。那么为什么选择保证前置接结点的原子性呢?从操作来看:
设置后置域需要两个 CAS 操作,即 tail.next = node,然后把 tail 指针设置为当前结点。这两个操作必须原子性进行。
设置前置域只需要一个 CAS 操作,即设置 tail 指针。你可能会问,不需要设置 node.prev = tail 吗,当然需要,但是此时 Node 结点是没有进入队列的,我们对 Node 结点操作不存在竞争问题,也就不需要保证 CAS 操作,只需要在后面设置 tail 指针时进行一次 CAS 操作,如果 CAS 操作失败表示 tail 已经被改变,重新设置 node.prev = tail,直至 CAS 操作成功从而保证了前置域的原子性。这块我没弄明白,请参照—— 锁原理 - AQS 源码分析 。弄懂了请在下面评论。
3、明知道 node.next 有可见性问题,为什么还要设计成双向链表?
唤醒同步线程时,如果有后继结点,那么时间复杂为 O(1)。否则只能只反向遍历,时间复杂度为 O(n)。通过上面的 CAS 入队操作我们知道 node.prev 一定是线程安全的。而 node.next 并不是通过 CAS 设置的,所以不一定是正确的。一般会认为以下两种情况中 node.next 是不可靠的,需要从 tail 反向遍历:
private void unparkSuccessor(Node node) {
//获取当前结点的状态
int ws = node.waitStatus;
if (ws < 0)
//将当前结点的状态设置为默认值 0
node.compareAndSetWaitStatus(ws, 0);
Node s = node.next; //获取当前结点的后继结点
//如果下一个结点为空,或者下一个结点的状态为 CANCELLED
if (s == null || s.waitStatus > 0) {
s = null;
//从尾结点开始从后往前开始遍历找到队列第一个waitStatus<=0的节点。(重点)
for (Node p = tail; p != node && p != null; p = p.prev)
// 如果是独占式,这里小于0,其实就是 SIGNAL
if (p.waitStatus <= 0)
s = p;
}
//如果当前节点的下个节点不为空,而且状态<=0,就把唤醒下个结点的线程
if (s != null)
LockSupport.unpark(s.thread);
}
public
class ConditionObject
implements
Condition, java.io.Serializable {
private
static
final
long serialVersionUID = 1173984872572414699L
;
//
该类中只有两个成员变量
private
transient Node firstWaiter;
//
条件队列的第一个结点
private
transient Node lastWaiter;
//
条件队列的最后一个结点
//
公有的构造函数,用于创建一个新结点
public
ConditionObject() { }
//
私有方法,添加一个条件等待结点
private
Node addConditionWaiter() {
//
判断线程是否正在独占资源,需要子类重写
if (!isHeldExclusively())
//
如果是独占资源就抛出异常
throw
new
IllegalMonitorStateException();
Node t = lastWaiter;
//
记录下最后一个等待结点
//
如果t不为空并且不是CONDITION状态,那么肯定是CANCELL状态
if (t !=
null && t.waitStatus !=
Node.CONDITION) {
unlinkCancelledWaiters();
//
清除掉所有的已取消的结点
t = lastWaiter;
//
此时t如果不为空,一定未被取消
}
//
新建一个CONDITION状态的结点用于封装当前线程
Node node =
new
Node(Node.CONDITION);
//
如果t为空,表示等待队列还未建立,就将node设为头结点,即第一个结点
if (t ==
null
)
firstWaiter =
node;
else
//
如果队列已经存在其它结点,就将node结点加到队列最后一个结点后面
t.nextWaiter =
node;
lastWaiter = node;
//
将最后一个结点设置为node,即使node是第一个结点
return
node;
}
//
内部方法,唤醒队列的第一个结点
private
void
doSignal(Node first) {
do
{
//
此处判断结点的后继结点是否为空,同时已经移动了firstWaiter指针
if ( (firstWaiter = first.nextWaiter) ==
null
)
lastWaiter =
null;
//
如果后继结点为空,那么将条件队列置空
//
上面的if中firstWaiter指针已经移动到first的下一个结点,此处将first出队
first.nextWaiter =
null
;
//
不断将结点加入到 syn 队列中,直至该结点为空或者已被取消
}
while (!transferForSignal(first) &&
(first = firstWaiter) !=
null
);
}
//
该方法与doSignal类似,不过不论当前结点是否已被取消都会加入到 syn 队列中
private
void
doSignalAll(Node first) {
lastWaiter = firstWaiter =
null
;
do
{
Node next =
first.nextWaiter;
first.nextWaiter =
null
;
transferForSignal(first);
first =
next;
}
while (first !=
null
);
}
//
移除所有的已取消的结点
private
void
unlinkCancelledWaiters() {
Node t =
firstWaiter;
Node trail =
null
;
while (t !=
null
) {
Node next =
t.nextWaiter;
if (t.waitStatus !=
Node.CONDITION) {
t.nextWaiter =
null
;
//
第一次进来trail才会为null,也就是头结点已被取消
if (trail ==
null
)
firstWaiter =
next;
else
//
trail记录的是前置结点,此处清除结点 t
trail.nextWaiter =
next;
//
不断循环lastWaiter始终指向当前循环的最以一个未取消的结点
if (next ==
null
)
lastWaiter =
trail;
}
else
trail =
t;
t =
next;
}
}
//
公有方法,类外可以调用,用于将等待队列中的结点加入到同步队列
public
final
void
signal() {
//
如果是独占模式就抛出异常
if (!
isHeldExclusively())
throw
new
IllegalMonitorStateException();
Node first =
firstWaiter;
if (first !=
null
)
doSignal(first);
//
注意,该方法在遇到已取消的结点时会停止
}
//
公有方法,唤醒等待队列中所有的结点
public
final
void
signalAll() {
if (!
isHeldExclusively())
throw
new
IllegalMonitorStateException();
Node first =
firstWaiter;
if (first !=
null
)
doSignalAll(first);
//
无论是否以被取消,都会加入到同步队列
}
//
等待,当前线程在接到信号之前一直处于等待状态,不响应中断
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();
}
/*
* 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.
*/
//
这是一个很复杂的判断,用了两个三目表达式,作用是如果新建的等待节点所在线程中断,
//
则把节点的状态由CONDITION更新为0,并且加入到同步等待队列中,返回THROW_IE中断状态,如果加入同步队列失败,返回REINTERRUPT
//
如果新建的等待节点所在线程没有中断,返回0,也就是初始状态的interruptMode
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.
*/
//
等待完毕后报告中断处理,前边的逻辑得到的interruptMode如果为THROW_IE则抛出InterruptedException,如果为REINTERRUPT则中断当前线程
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();
Node node = addConditionWaiter();
//
添加一个结点到等待队列
/*
fullyRelease释放当前AQS中的所有资源
其实也就是基于status的值调用release(status)
这一步对于锁实现来说,就是一个解锁操作
释放失败则标记等待状态为取消
*/
int savedState = fullyRelease(node);
//
获取释放的状态
int interruptMode = 0;
//
初始化中断
//
如果节点新建的节点不位于同步队列中(理论上应该是一定不存在),
//
则对节点所在线程进行阻塞,第二轮循环理论上节点一定在同步等待队列中
while (!
isOnSyncQueue(node)) {
LockSupport.park(
this);
//
阻塞线程
//
如果线程被中断就结束循环,并且设置中断标志
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0
)
break
;
}
//
节点所在线程被唤醒后,如果节点所在线程没有处于中断状态,则以独占模式进行头节点竞争
//
注意这里使用的state是前面释放资源时候返回的保存下来的state
if (acquireQueued(node, savedState) && interruptMode !=
THROW_IE)
interruptMode =
REINTERRUPT;
//
下一个等待节点不空,则从等待队列中移除所有取消的等待节点
if (node.nextWaiter !=
null)
//
clean up if cancelled
unlinkCancelledWaiters();
//
interruptMode不为0则按照中断模式进行不同的处理
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();
//
We don't check for nanosTimeout <= 0L here, to allow
//
awaitNanos(0) as a way to "yield the lock".
final
long deadline = System.nanoTime() +
nanosTimeout;
long initialNanos =
nanosTimeout;
Node node =
addConditionWaiter();
int savedState =
fullyRelease(node);
int interruptMode = 0
;
while (!
isOnSyncQueue(node)) {
if (nanosTimeout <= 0L
) {
transferAfterCancelledWait(node);
break
;
}
if (nanosTimeout >
SPIN_FOR_TIMEOUT_THRESHOLD)
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);
long remaining = deadline - System.nanoTime();
//
avoid overflow
return (remaining <= initialNanos) ?
remaining : Long.MIN_VALUE;
}
/**
* 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();
//
We don't check for nanosTimeout <= 0L here, to allow
//
await(0, unit) as a way to "yield the lock".
final
long deadline = System.nanoTime() +
nanosTimeout;
Node node =
addConditionWaiter();
int savedState =
fullyRelease(node);
boolean timedout =
false
;
int interruptMode = 0
;
while (!
isOnSyncQueue(node)) {
if (nanosTimeout <= 0L
) {
timedout =
transferAfterCancelledWait(node);
break
;
}
if (nanosTimeout >
SPIN_FOR_TIMEOUT_THRESHOLD)
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<>
();
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;
}
}
添加结点到条件队列的过程
从条件队列中唤醒结点
4|5独占模式
AQS同步器如果使用独占(EXCLUSIVE)模式,那么意味着同一个时刻,只有唯一的一个结点所在线程获取(acuqire)原子状态 status 成功,此时该线程可以从阻塞状态解除继续运行,而同步队列中的其他节点持有的线程依然处于阻塞状态。独占模式同步器的功能主要由下面的四个方法提供:
1、acquire(int arg):申请获取 arg 个原子状态 status(申请成功可以简单理解为 status = status - arg)。
3、tryAcquireNanos(int arg, long nanosTimeout):申请获取 arg 个原子状态 status,带超时的版本。
4、release(int arg):释放 arg 个原子状态 status(释放成功可以简单理解为 status = status + arg)。
独占模式下,AQS同步器实例初始化时候传入的 status 值,可以简单理解为"允许申请的资源数量的上限值",独占模式下 arg 为 1。
独占锁的获取—— acquire
public final void acquire(int arg) {
//如果申请资源失败并且新增一个独占类型的结点到同步队列成功,就中断该线程,否则直接返回
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
public final void acquire(int arg) {
//如果申请资源失败并且新增一个独占类型的结点到同步队列成功,就中断该线程,否则直接返回
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
public final void acquireInterruptibly(int arg)
throws InterruptedException {
//如果线程已被中断,就抛出异常
if (Thread.interrupted())
throw new InterruptedException();
//尝试非阻塞式获取锁失败,就执行doAcquireInterruptibly
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
//独占式响应中断获取锁
private void doAcquireInterruptibly(int arg)
throws InterruptedException {
//基于当前线程新增一个独占的Node节点进入同步等待队列中
final Node node = addWaiter(Node.EXCLUSIVE);
try {
for (;;) {
//获取当前结点的前置结点
final Node p = node.predecessor();
//如果前置结点时头结点,且获取资源成功
if (p == head && tryAcquire(arg)) {
setHead(node); //设置头结点,即该节点出队
p.next = null; // help GC
return;
}
//当前结点被挂起
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
//当挂起的结点被唤醒时,不再设置中断状态
//如果线程是因为中断而被唤醒,则直接抛出异常
throw new InterruptedException();
}
} catch (Throwable t) {
//捕获异常,取消结点
cancelAcquire(node);
throw t;
}
}
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
//如果获取锁成功就直接返回true
return tryAcquire(arg) ||
doAcquireNanos(arg, nanosTimeout); //否则执行该方法
}
//doAcquireNanos方法用到的常量
static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1000L;
private boolean doAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
//超时时间内没有获取到锁,直接返回false
if (nanosTimeout <= 0L)
return false;
//计算超时截止的最终时间,为系统纳秒 + 超时时限
final long deadline = System.nanoTime() + nanosTimeout;
//以独占的方式加入到同步队列
final Node node = addWaiter(Node.EXCLUSIVE);
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
return true;
}
//计算新的超时时间
nanosTimeout = deadline - System.nanoTime();
//如果超时,取消结点并返回false
if (nanosTimeout <= 0L) {
cancelAcquire(node);
return false;
}
if (shouldParkAfterFailedAcquire(p, node) &&
//判断最新的超时时限是否大于1000
nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
//将线程挂起 nanosTimeout 长时间,时间到,自动返回
//在下一次循环时会返回false
LockSupport.parkNanos(this, nanosTimeout);
//如果线程在这期间被中断过,就抛出异常
if (Thread.interrupted())
throw new InterruptedException();
}
} catch (Throwable t) {
//线程被中断,取消结点
cancelAcquire(node);
throw t;
}
}
/**
* The number of nanoseconds for which it is faster to spin
* rather than to use timed park. A rough estimate suffices
* to improve responsiveness with very short timeouts.
*/