聊聊JUC包下的底层支撑类-AbstractQueuedSynchronizer(AQS)

科技资讯 投稿 6800 0 评论

聊聊JUC包下的底层支撑类-AbstractQueuedSynchronizer(AQS)

聊聊JUC包下的底层支撑类-AbstractQueuedSynchronizer(AQS

一、AQS是什么

    AQS全称AbstractQueuedSynchronizer即抽象队列同步器,可以理解成是一个可以实现锁的框架(基类,它可以实现共享和独占两种模式的锁,事实上juc包下很多关于锁的工具类也是基于AQS的;它提供了一些模板方法供子类实现拓展,并且本身结合底层的Unsafe类实现了基于cpu原语层的安全操作,从而实现在并发环境下的线程安全

二、AQS的实现原理

    AQS能作为基类来实现锁的功能主要原因来自于它维护的一个int类型的state变量和一个FIFO的双向队列;实现类可以根据自身的需求,通过控制state的值来决定线程是否需要阻塞,而双向队列用来存放没有争抢到锁资源的线程;并且AQS通过结合Unsafe类的能力封装了可以线程安全的操作state值的方法(一堆CAS的操作方法,这样程序员就可以只关注锁的使用而不必关注底层实现的细节了;
  • AQS支持两种模式锁的实现,分别是独占锁和共享锁,独占锁的具体实现以ReentrantLock为代表,共享锁的实现诸如CountDownLatch、CyclicBarrier等

注:由于后续会介绍AQS的源码以及子类实现,所以这里只是大白话般的描述了一下AQS的原理,即两个关键:一个state一个双向队列,其实要展开还有许多细节要聊,考虑到这些细节后续源码里会有体现这里就不再表述了

三、AQS的源码简析

1、state变量

private volatile int state;

1、state是AQS提供的供子类拓展的一个同步状态,子类可以维护state的不同状态来实现不同效果的锁实现,如ReentrantLock就是通过维护state是否为0或1来表示锁的加解操作;

2、Node内部类

    Node类是双向CLH队列的构成元素,其维护的thread变量就是没有争抢到锁的线程,然后还维护了CLH队列的其他几个关键信息,如当前Node的前置节点(prev、后续节点(next等,下面贴上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对应的值,指示线程正在等待condition唤醒*/
    static final int CONDITION = -2;
    /**
     * waitStatus value to indicate the next acquireShared should
     * unconditionally propagate
     */
    static final int PROPAGATE = -3;

    /**
     * 等待状态,枚举值有1,0,-1,-2,-3分别对应上面的几个变量值,0表示以上状态都不是
     */
    volatile int waitStatus;

    /**
     * 当前Node的前置节点
     */
    volatile Node prev;

    /**
     * 当前Node的后继节点
     */
    volatile Node next;

    /**
     * 与当前Node绑定的被阻塞的线程
     */
    volatile Thread thread;

    /**
     * 下一个等待节点,Condition状态下要用到
     */
    Node nextWaiter;

    /**
     * 如果节点在共享模式下等待,则返回true。
     */
    final boolean isShared( {
        return nextWaiter == SHARED;
    }

    /**
     * 获取当前队列的前置节点
     *
     * @return the predecessor of this node
     */
    final Node predecessor( throws NullPointerException {
        Node p = prev;
        if (p == null
            throw new NullPointerException(;
        else
            return p;
    }

    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;
    }
}

3、AQS供子类拓展的模板方法

独占模式供子类实现的方法

    tryAcquire(int 尝试获取锁,获取成功返回true,失败返回false

共享模式供子类实现的方法

    tryAcquireshared(int

  • tryReleaseshared(int

上面简单介绍了一下AQS的原理以及源码的部分注释,接下来我会写一篇ReentrantLock源码解读的相关文章,来体验下AQS的实际用处

编程笔记 » 聊聊JUC包下的底层支撑类-AbstractQueuedSynchronizer(AQS)

赞同 (33) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽