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开发validate方法中校验工具类详解

    java开发validate方法中校验工具类详解

    这篇文章主要为大家介绍了java开发validate方法中校验工具类详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • Java多线程的用法详细介绍

    Java多线程的用法详细介绍

    这篇文章主要介绍了Java多线程的用法详细介绍的相关资料,希望通过本文能帮助到大家,需要的朋友可以参考下
    2017-09-09
  • Java如何将处理完异常之后的程序能够从抛出异常的地点向下执行?

    Java如何将处理完异常之后的程序能够从抛出异常的地点向下执行?

    今天小编就为大家分享一篇关于Java如何将处理完异常之后的程序能够从抛出异常的地点向下执行?,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-04-04
  • Java集合排序规则接口Comparator用法解析

    Java集合排序规则接口Comparator用法解析

    这篇文章主要介绍了Java集合排序规则接口Comparator用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09
  • 基于maven install 没反应的解决方法

    基于maven install 没反应的解决方法

    下面小编就为大家带来一篇基于maven install 没反应的解决方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • mybatis if test条件判断语句中的判断问题分析

    mybatis if test条件判断语句中的判断问题分析

    这篇文章主要介绍了mybatis if test条件判断语句中的判断问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • 深入分析Java并发编程之CAS

    深入分析Java并发编程之CAS

    这篇文章主要介绍了Java并发编程之CAS的相关资料,帮助大家更好的理解和学习Java并发编程,感兴趣的朋友可以了解下
    2020-08-08
  • Java 注解@PostConstruct的原理及最佳使用场景分析

    Java 注解@PostConstruct的原理及最佳使用场景分析

    @PostConstruct 是 Java 中非常实用的注解,尤其是在 Spring 等框架中,它使得开发者可以方便地在 Bean 初始化后执行额外的操作,本文给大家介绍@PostConstruct 的原理、使用场景及最佳实践,感兴趣的朋友一起看看吧
    2025-04-04
  • IntelliJ IDEA下自动生成Hibernate映射文件以及实体类

    IntelliJ IDEA下自动生成Hibernate映射文件以及实体类

    这篇文章主要介绍了IntelliJ IDEA下自动生成Hibernate映射文件以及实体类,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-11-11
  • Java使用POI从Excel读取数据并存入数据库(解决读取到空行问题)

    Java使用POI从Excel读取数据并存入数据库(解决读取到空行问题)

    有时候需要在java中读取excel文件的内容,专业的方式是使用java POI对excel进行读取,这篇文章主要给大家介绍了关于Java使用POI从Excel读取数据并存入数据库,文中介绍的办法可以解决读取到空行问题,需要的朋友可以参考下
    2023-12-12

最新评论