`
粟谷_sugu
  • 浏览: 25453 次
社区版块
存档分类
最新评论

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

阅读更多
本来准备写一篇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在其中扮演的就是作为在等待队伍中排队的节点的角色。然后节点中维护了前后节点的指针,所以可以在资源使用结束后通知排在后面的节点开始抢占。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics