AbstractQueuedSynchronizer内部类Node使用讲解
作者:今夜有点儿凉
这篇文章主要为大家介绍了AbstractQueuedSynchronizer内部类Node使用讲解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
Node类源码
以下是Node类源码,同时附上了代码解释:
static final class Node { /** 用于表示节点正在以共享模式等待的标记 */ static final Node SHARED = new Node(); /** 用于表示节点正在以独占模式等待的标记 */ static final Node EXCLUSIVE = null; /** waitStatus的值,表示线程已被取消 */ static final int CANCELLED = 1; /** waitStatus的值,表示后继节点的线程需要被唤醒 */ static final int SIGNAL = -1; /** waitStatus的值,表示线程正在等待条件 */ static final int CONDITION = -2; /** * waitStatus的值,表示下一个acquireShared操作应该无条件地传播 */ static final int PROPAGATE = -3; /** * 状态字段,只有以下几个取值: * SIGNAL: 后继节点的线程被阻塞(通过park方法),因此当前节点在释放或取消时必须唤醒其后继节点。 * 为了避免竞争条件,acquire方法必须首先表明它们需要一个信号,然后重试原子性的acquire操作, * 失败后再阻塞。 * CANCELLED: 由于超时或中断,该节点被取消。节点一旦进入这个状态就不会再离开。 * 特别地,被取消的线程不会再次阻塞。 * CONDITION: 该节点当前在条件队列中。在转移时,它将不再用作同步队列节点, * 此时状态将被设置为0。(在这里使用该值与字段的其他用途无关,但简化了机制。) * PROPAGATE: 需要将releaseShared操作传播到其他节点。这个值(仅用于头节点)在doReleaseShared中设置, * 以确保传播继续,即使在此期间有其他操作进行。 * 0: 无上述状态 * * 这些值按照数值顺序排列,以简化使用。非负值表示节点不需要发出信号。 * 因此,大多数代码不需要检查特定的值,只需要检查符号即可。 * * 对于普通的同步节点,该字段初始化为0;对于条件节点,初始化为CONDITION。 * 该字段使用CAS(或在可能的情况下,无条件的volatile写操作)进行修改。 */ volatile int waitStatus; /** * 前驱节点的链接,当前节点/线程依赖于它来检查waitStatus。 * 在入队时分配,并在出队时置空(为了进行垃圾回收)。 * 当前驱节点被取消时,我们会快速找到一个非取消的前驱节点, * 因为头节点永远不会被取消:只有成功获取锁的结果才会成为头节点。 * 取消的线程永远不会成功获取锁,而且只有线程自己可以取消,而不是其他节点。 */ volatile Node prev; /** * 后继节点的链接,在释放时当前节点/线程将其唤醒。 * 在入队时进行调整以跳过已取消的前驱节点,并在出队时置空(为了进行垃圾回收)。 * 在enq操作中,直到附加之后才给前驱节点的next字段赋值, * 因此看到一个空的next字段并不一定意味着节点在队列末尾。 * 但是,如果next字段看起来为空,我们可以从尾部向前扫描prev节点来进行双重检查。 * 取消的节点的next字段被设置为指向节点自身,而不是null, * 这样可以简化isOnSyncQueue方法的实现。 */ volatile Node next; /** * 入队该节点的线程。在构造时初始化,并在使用后置空。 */ volatile Thread thread; /** * 链接到下一个在条件上等待的节点,或者特殊值SHARED。 * 因为条件队列只有在持有独占模式时才会访问, * 所以我们只需要一个简单的链式队列来保存节点, * 而它们在等待条件时会被转移到同步队列中以重新获取锁。 * 由于条件只能是独占的,所以我们通过使用特殊值来表示共享模式来节省一个字段。 */ Node nextWaiter; /** * 如果节点在共享模式下等待,则返回true。 */ final boolean isShared() { return nextWaiter == SHARED; } /** * 返回前驱节点,如果前驱节点为null,则抛出NullPointerException异常。 * 当无法为null时使用,可以省略空检查,但为了帮助虚拟机,这里进行了空检查。 * * @return 当前节点的前驱节点 */ final Node predecessor() throws NullPointerException { Node p = prev; if (p == null) throw new NullPointerException(); else return p; } Node() { // 用于建立初始头节点或SHARED标记 } Node(Thread thread, Node mode) { // 由addWaiter方法使用 this.nextWaiter = mode; this.thread = thread; } Node(Thread thread, int waitStatus) { // 由Condition使用 this.waitStatus = waitStatus; this.thread = thread; } }
这段代码定义了一个内部类Node
,用于构建同步队列或条件队列等数据结构。
代码解释
Node
类有一些静态常量,如SHARED
和EXCLUSIVE
,它们分别表示共享模式和独占模式的节点。这些常量用于区分不同类型的节点。Node
类有一个waitStatus
字段,用于表示节点的等待状态。具体的状态值有CANCELLED
、SIGNAL
、CONDITION
、PROPAGATE
和0,分别表示节点被取消、后继节点需要唤醒、节点在条件队列中等待、需要传播信号以及无特殊状态。这些状态用于控制线程的等待和唤醒。Node
类有一个prev
字段和一个next
字段,分别表示前驱节点和后继节点。这些字段用于构建队列结构,并且在节点入队和出队时进行相应的调整。Node
类有一个thread
字段,表示当前节点对应的线程。Node
类有一个nextWaiter
字段,用于在条件队列中表示下一个等待的节点,或者用SHARED
特殊值表示共享模式。isShared()
方法返回一个布尔值,表示节点是否在共享模式下等待。predecessor()
方法返回前驱节点,如果前驱节点为null
,则抛出NullPointerException
异常。Node
类有多个构造函数,用于创建不同类型的节点。其中,一个构造函数用于addWaiter
方法,另一个构造函数用于Condition
。
总结
这段代码实现了一个用于同步队列或条件队列的节点数据结构,用于管理等待线程的状态和关系。通过这些节点,可以实现线程的等待和唤醒机制。
以上就是AbstractQueuedSynchronizer内部类Node使用讲解的详细内容,更多关于AbstractQueuedSynchronizer内部类Node的资料请关注脚本之家其它相关文章!