java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > AbstractQueuedSynchronizer内部类Node

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,用于构建同步队列或条件队列等数据结构。

代码解释

总结

这段代码实现了一个用于同步队列或条件队列的节点数据结构,用于管理等待线程的状态和关系。通过这些节点,可以实现线程的等待和唤醒机制。

以上就是AbstractQueuedSynchronizer内部类Node使用讲解的详细内容,更多关于AbstractQueuedSynchronizer内部类Node的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文