这里先重点分析一下AQS中等待队列的节点AQS的静态内部类Node的源码:
static final class Node { // 标记一个节点处于共享模式下的等待 static final Node SHARED = new Node(); // 标记一个节点处于独占模式下的等待 static final Node EXCLUSIVE = null; // 取消状态 static final int CANCELLED = 1; // 唤醒状态 static final int SIGNAL = -1; // 条件等待状态 static final int CONDITION = -2; // 传播状态 static final int PROPAGATE = -3; // 等待状态,初始值为0,其他可选值是上面的4个值 volatile int waitStatus; // 当前节点前驱节点的引用 volatile Node prev; // 当前节点后继节点的引用 volatile Node next; // 当前节点持有的线程,可能是阻塞中等待唤醒的线程 volatile Thread thread; // 下一个等待节点 Node nextWaiter; // 当前操作的节点是否处于共享模式 final boolean isShared() { return nextWaiter == SHARED; } // 获取当前节点的前驱节点,确保前驱节点必须存在,否则抛出NPE final Node predecessor() { Node p = prev; if (p == null) throw new NullPointerException(); else return p; } // 空节点,主要是首次创建队列的时候创建的头和尾节点使用 Node() {} // 设置下一个等待节点,设置持有线程为当前线程 Node(Node nextWaiter) { this.nextWaiter = nextWaiter; THREAD.set(this, Thread.currentThread()); } // 设置waitStatus,设置持有线程为当前线程 Node(int waitStatus) { WAITSTATUS.set(this, waitStatus); THREAD.set(this, Thread.currentThread()); } // CAS更新waitStatus final boolean compareAndSetWaitStatus(int expect, int update) { return WAITSTATUS.compareAndSet(this, expect, update); } // CAS设置后继节点 final boolean compareAndSetNext(Node expect, Node update) { return NEXT.compareAndSet(this, expect, update); } // 设置前驱节点 final void setPrevRelaxed(Node p) { PREV.set(this, p); } // 下面是变量句柄的实现,在VarHandle出现之前使用的是Unsafe,其实底层还是照样使用Unsafe private static final VarHandle NEXT; private static final VarHandle PREV; private static final VarHandle THREAD; private static final VarHandle WAITSTATUS; static { try { MethodHandles.Lookup l = MethodHandles.lookup(); NEXT = l.findVarHandle(Node.class, "next", Node.class); PREV = l.findVarHandle(Node.class, "prev", Node.class); THREAD = l.findVarHandle(Node.class, "thread", Thread.class); WAITSTATUS = l.findVarHandle(Node.class, "waitStatus", int.class); } catch (ReflectiveOperationException e) { throw new ExceptionInInitializerError(e); } } }其中,变量句柄(VarHandle)是JDK9引入的新特性,其实底层依赖的还是Unsafe的方法,笔者认为可以简单理解它为Unsafe的门面类,而定义的方法基本都是面向变量属性的操作。这里需要关注一下Node里面的几个属性:
waitStatus:当前Node实例的等待状态,可选值有5个。
初始值整数0:当前节点如果不指定初始化状态值,默认值就是0,侧面说明节点正在等待队列中处于等待状态。
Node#CANCELLED整数值1:表示当前节点实例因为超时或者线程中断而被取消,等待中的节点永远不会处于此状态,被取消的节点中的线程实例不会阻塞。
Node#SIGNAL整数值-1:表示当前节点的后继节点是(或即将是)阻塞的(通过LockSupport#park()),当它释放或取消时,当前节点必须LockSupport#unpark()它的后继节点。
Node#CONDITION整数值-2:表示当前节点是条件队列中的一个节点,当它转换为同步队列中的节点的时候,状态会被重新设置为0。
Node#PROPAGATE整数值-3:此状态值通常只设置到调用了doReleaseShared()方法的头节点,确保releaseShared()方法的调用可以传播到其他的所有节点,简单理解就是共享模式下节点释放的传递标记。
prev、next:当前Node实例的前驱节点引用和后继节点引用。
thread:当前Node实例持有的线程实例引用。
nextWaiter:这个值是一个比较容易令人生疑的值,虽然表面上它称为"下一个等待的节点",但是实际上它有三种取值的情况。
值为静态实例Node.EXCLUSIVE(也就是null),代表当前的Node实例是独占模式。
值为静态实例Node.SHARED,代表当前的Node实例是共享模式。
值为非Node.EXCLUSIVE和Node.SHARED的其他节点实例,代表Condition等待队列中当前节点的下一个等待节点。
Node类的等待状态waitStatus理解起来是十分费劲的,下面分析AQS其他源码段的时候会标识此状态变化的时机。