当前位置: 移动技术网 > IT编程>开发语言>Java > Java并发编程-AQS数据结构和图解

Java并发编程-AQS数据结构和图解

2020年07月13日  | 移动技术网IT编程  | 我要评论

AQS的概念:

  队列同步器 是用来构建锁和其他基础并发组件的框架。内部维护了一个state,维护同步器状态,一个双向队列维护等待线程排队工作。运用了模板方法模式,父类抽取了公共代码和执行逻辑,子类继承复写定制化方法即可。

数据结构:

成员:    
            Node head; 头节点
            
            Node tail;  尾节点
            
            int state;    state=0 表示释放锁    state>0 表示占有锁  操作state的方法: getState   setState  compareAndSetState

主要方法:

        void acquire(int arg)
        boolean release(int arg)
        void acquireInterruptibly(int arg)
        boolean doAcquireNanos(int arg, long nanosTimeout)
         
        void acquireShared(int arg)
        boolean releaseShared(int arg)
        void acquireSharedInterruptibly(int arg)
        boolean tryAcquireSharedNanos(int arg, long nanosTimeout)

Node是内部维护的一个CLH队列。CLH 同步队列是一个 FIFO 双向队列,AQS 依赖它来完成同步状态的管理

CLH的数据结构:

Node :
    static final Node SHARED = new Node(); // 共享模式
    static final Node EXCLUSIVE = null; // 独占模式
    
     /**
     * 因为超时或者中断,节点会被设置为取消状态,被取消的节点时不会参与到竞争中的,他会一直保持取消状态不会转变为其他状态
     */
    static final int CANCELLED =  1; 取消
    /**
     * 后继节点的线程处于等待状态,而当前节点的线程如果释放了同步状态或者被取消,将会通知后继节点,使后继节点的线程得以运行
     */
    static final int SIGNAL    = -1;  排队等待被唤醒拿锁
    /**
     * 节点在等待队列中,节点线程等待在Condition上,当其他线程对Condition调用了signal()后,该节点将会从等待队列中转移到同步队列中,加入到同步状态的获取中
     */
    static final int CONDITION = -2;  等待在等待队列中,condition上,唤醒后加入同步队列
    /**
     * 表示下一次共享式同步状态获取,将会无条件地传播下去
     */
    static final int PROPAGATE = -3;  
    
    
    volatile int waitStatus; // 等待的状态  value对应上面几个状态  用来控制线程阻塞和唤醒
    
    // 前驱
    volatile Node prev;

    /** 后继节点 */
    volatile Node next;
     
     Node nextWaiter; //  等待队列中的后续节点, 获取同步的模型(Mode)共享还是独占
                          tryAcquire() tryAcquireShared() 会分别独占和共享的获取同步状态,获取失败时,会调用addWaiter入队
                           nextWaiter 就表示是入队node的类型
   
    // 拿到锁的线程
     volatile Thread thread;

     predecessor()  node的前一个节点
     
     node() 共享
     Node(Thread thread, Node mode)  按mode创建
  

 入队方法(addWaiter):
        1、获取tail  node p = tail;
        2、p.next = node
        3、node.pre = p;
        4、tail = node; compareAndSetTail AQS放
        5、enq() AQS没成功,就自旋放

 

出队 setHead  -- 在acquireQueue内被唤醒时调用:
        1、 head指向当前 head = node;
        2、 node.thread = null;   
        3、 当前节点断开prenode.prev = null;

acquire内部逻辑图:

本文地址:https://blog.csdn.net/early_or_later/article/details/107304828

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网