AbstractQueuedSynchronizer内部类Node使用讲解

 更新时间:2023年07月23日 12:41:31   作者:今夜有点儿凉  
这篇文章主要为大家介绍了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类有一些静态常量,如SHAREDEXCLUSIVE,它们分别表示共享模式和独占模式的节点。这些常量用于区分不同类型的节点。
  • Node类有一个waitStatus字段,用于表示节点的等待状态。具体的状态值有CANCELLEDSIGNALCONDITIONPROPAGATE和0,分别表示节点被取消、后继节点需要唤醒、节点在条件队列中等待、需要传播信号以及无特殊状态。这些状态用于控制线程的等待和唤醒。
  • Node类有一个prev字段和一个next字段,分别表示前驱节点和后继节点。这些字段用于构建队列结构,并且在节点入队和出队时进行相应的调整。
  • Node类有一个thread字段,表示当前节点对应的线程。
  • Node类有一个nextWaiter字段,用于在条件队列中表示下一个等待的节点,或者用SHARED特殊值表示共享模式。
  • isShared()方法返回一个布尔值,表示节点是否在共享模式下等待。
  • predecessor()方法返回前驱节点,如果前驱节点为null,则抛出NullPointerException异常。
  • Node类有多个构造函数,用于创建不同类型的节点。其中,一个构造函数用于addWaiter方法,另一个构造函数用于Condition

总结

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

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

相关文章

  • Java设计模式之java外观模式详解

    Java设计模式之java外观模式详解

    这篇文章主要介绍了Java设计模式之外观模式(Facade模式)介绍,外观模式(Facade)的定义:为子系统中的一组接口提供一个一致的界面,需要的朋友可以参考下
    2021-09-09
  • Java杂谈之重复代码是什么

    Java杂谈之重复代码是什么

    刚开始工作时,总有人开玩笑说,编程实际上就是 CV,调侃很多程序员写程序依靠的是复制粘贴。至今,很多初级甚至高级程序员写代码依旧是CV,就是把其他项目里的一段代码复制过来,稍加改动,然后,跑一下没有大问题就完事。这就是在给其他人挖坑
    2021-09-09
  • Java获取http和https协议返回的json数据

    Java获取http和https协议返回的json数据

    本篇文章主要介绍了Java获取http和https协议返回的json数据 ,本篇文章提供两个方法,帮助各位如何获取http和https返回的数据。有兴趣的可以了解一下。
    2017-01-01
  • StringBuilder为什么线程不安全深入讲解

    StringBuilder为什么线程不安全深入讲解

    这篇文章主要给大家介绍了关于StringBuilder为什么线程不安全的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用StringBuilder线程具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-08-08
  • SpringBoot应用启动内置Tomcat的过程源码分析

    SpringBoot应用启动内置Tomcat的过程源码分析

    这篇文章主要介绍了SpringBoot应用启动内置Tomcat的过程分析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-07-07
  • Java Web 简单的分页显示实例代码

    Java Web 简单的分页显示实例代码

    这篇文章主要介绍了Java Web 简单的分页显示实例代码的相关资料,本文通过,计算总的页数和查询指定页数据两个方法实现分页效果,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-06-06
  • Mybatis 中如何判断集合的size

    Mybatis 中如何判断集合的size

    这篇文章主要介绍了在Mybatis中判断集合的size操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • SpringBoot利用限速器RateLimiter实现单机限流的示例代码

    SpringBoot利用限速器RateLimiter实现单机限流的示例代码

    本文主要介绍了SpringBoot利用限速器RateLimiter实现单机限流的示例代码,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • JAVA基础快速从入门到精通

    JAVA基础快速从入门到精通

    Java是一门面向对象的编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征
    2022-03-03
  • 解决MyEclipse中Maven设置jdk版本jdk1.8报错问题

    解决MyEclipse中Maven设置jdk版本jdk1.8报错问题

    今天安装了jdk1.8、tomcat8、和maven3.5.2,弄好后在myeclipse新建了一个maven项目,项目默认是jdk1.5,改成jdk1.8后项目报错
    2018-10-10

最新评论