欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java的JUC包系列文章(一): AQS的初探文章---说一说 Node  

程序员文章站 2024-02-02 08:35:40
...
本来准备写一篇AQS的完成解析,已经写了大部分了,但是觉得写得实在太乱了,而且很多细节的东西很难讲清楚,所以还是决定先写一些前文,都是属于AQS整体的一部分,也都是AQS的灵魂组件,所以单拎出来说一下。
本文先争取将贯穿AQS的一个组件先讲清楚。好了,直接进入本文的主题,AQS的内部类--Node
(一)  Node是什么,为什么这么重要
Node是AQS中的一个静态的内部类,之所以说贯穿了AQS的整个实现是因为AQS是一个竞争锁的并发框架, 有竞争就会有失败,所以所有的失败的节点都会以Node的形式,等待在等待者队列中,知道放弃竞争了,或者竞争成功。
构建Node的时候都需要两个参数,一个是Thread,标识是哪个线程在等待,那当轮到你竞争的时候也会知道去唤醒哪个Thread进行工作,还有一个是Node.mode,这个是Node内部实现的标识当前Node是数据哪种竞争模式的,有两种不同的模式,独占模式(exclusive)和共享模式(Shared)
独占模式:资源是独占的,一次只能一个线程获取。
共享模式:同时可以被多个线程获取,具体的资源的个数可以通过参数指定。
直接看一下Node的代码
	static final class Node {
        //标识为共享模式
        static final Node SHARED = new Node();
        //标识为独占模式
        static final Node EXCLUSIVE = null;

        /**
        * 以下四个都是Node的状态
        /

        // 标识当前Node取消了竞争
        static final int CANCELLED =  1;
        // 表示Node的后继结点可以被唤醒了
        static final int SIGNAL    = -1;
        // 表示现在Node阻塞者等待某些条件满足
        static final int CONDITION = -2;
        // #TODO
        static final int PROPAGATE = -3;

        volatile int waitStatus;
        
        // 在等待队列中的前一个节点 
        volatile Node prev;
        // 在等待队列中的后一个节点 
        volatile Node next;
        // 执行的线程
        volatile Thread thread;
        
        Node nextWaiter;

        final boolean isShared() {
            return nextWaiter == SHARED;
        }

        Node() {    // Used to establish initial head or SHARED marker
        }

        Node(Thread thread, Node mode) {     // Used by addWaiter
            this.nextWaiter = mode;
            this.thread = thread;
        }

        Node(Thread thread, int waitStatus) { // Used by Condition
            this.waitStatus = waitStatus;
            this.thread = thread;
        }
    }
    // 等待队列中的首节点
    private transient volatile Node tail;
    // 等待队列中的尾节点
    private transient volatile Node head;

	

所以,根据定义我们可以画出AQS中等待者队列的模型
(二)  Node的用处
在本系列的后面的文章中,我们会讲到,跟Node的模式分配一样,抢占资源也会有独占式和共享式的方法入口,AQS也留了供用户自定义的抢占逻辑方法。所以Node在整个框架中哪里用到呢?我们可以先自己想一下,如果自己设计一个最简单的抢占模型会怎么设计?肯定会有下面几个步骤
1: 提供一个资源供大家抢占,假设初始状态为1,被占用后设置为0.所以假设有多个线程去获取这个资源的时候,肯定会只有一个线程能抢占成功,那么其他的线程必须按序排好。同时也要考虑到多个节点往队伍中排会出现的并发问题
2: 当上一个节点消费完成后,要将资源释放出来,然后要通知排在队伍中的第一个节点,通知他可以开始竞争资源了。

在AQS框架中,大致的逻辑和我们想的差不多,而Node在其中扮演的就是作为在等待队伍中排队的节点的角色。然后节点中维护了前后节点的指针,所以可以在资源使用结束后通知排在后面的节点开始抢占。