状态变量state被volatile修饰,对其操作的方法包括tryAcquire、tryRelease等,都是通过CAS。
申请公平锁的线程,会先判断当前队列没有前驱节点在等待(也就是没有线程在等待)时才会CAS修改同步状态变量。而申请非公平锁的线程,则会无视队列,直接CAS抢锁,如果不成功,再进入到队列等待唤醒。1
上述判断有无线程在等待的方法如下,可见为从队列尾部往前遍历:
public final boolean hasQueuedPredecessors() {
Node h, s;
if ((h = head) != null) {
if ((s = h.next) == null || s.waitStatus > 0) {
s = null; // traverse in case of concurrent cancellation
for (Node p = tail; p != h && p != null; p = p.prev) {
if (p.waitStatus <= 0)
s = p;
}
}
if (s != null && s.thread != Thread.currentThread())
return true;
}
return false;
}
而对于队列中线程的唤醒机制,研究AQS的非公平锁与同步队列的FIFO冲突吗?,AQS之线程的阻塞和唤醒分析 等文章 和 JDK的unparkSuccessor(Node node)
方法(据我观察,入参node均为head),大致有以下结论:
当head的同步状态被释放后,需要唤醒后继节点。具体为从tail往head遍历,找到最前的一个阻塞节点。
条件队列
Lock的Condition会有这个。具体可查阅本博----朋熙面试(部分)二面中关于Monitor和AQS的部分