Java并发编程从入门到精通(二)-AQS源码分析(组成结构篇)

1、什么是AQS?
AQS全称,AbstractQueuedSynchronizer,意思大概就是“抽象队列同步器”,这个名词有点抽象,我们来先看看源码中的介绍,lalalalala…..,一大段英文。

/**
 * Provides a framework for implementing blocking locks and related
 * synchronizers (semaphores, events, etc) that rely on
 * first-in-first-out (FIFO) wait queues.  This class is designed to
 * be a useful basis for most kinds of synchronizers that rely on a
 * single atomic {@code int} value to represent state. Subclasses
 * must define the protected methods that change this state, and which
 * define what that state means in terms of this object being acquired
 * or released.  Given these, the other methods in this class carry
 * out all queuing and blocking mechanics. Subclasses can maintain
 * other state fields, but only the atomically updated {@code int}
 * value manipulated using methods {@link #getState}, {@link
 * #setState} and {@link #compareAndSetState} is tracked with respect
 * to synchronization.
 * */

翻译过来大概就是:
1、AQS是一个用于实现阻塞锁和相关同步器 (semaphores, events等等)的框架,它是基于FIFO等待队列的;
2、AQS是“以单个原子值(int)表示状态的同步器”的基础;
3、子类必须定义protected的方法来改变状态,还必须根据这个对象被acquired或released来定义状态的含义,且只能通过getState()、setState()、compareAndSetState()来更新状态值。

2、AQS的组成
这里没也什么好说的,与其说一大堆不如直接上源码看组成

public abstract class AbstractQueuedSynchronizer 
extends AbstractOwnableSynchronizer
implements java.io.Serializable {
    private static final long serialVersionUID = 7373984972572414691L;
    //构造方法
    protected AbstractQueuedSynchronizer() { }
    //定义了一个静态内部类Node
    //AQS内部维护了一个CLH队列,Node是这个队列的节点
    static final class Node {...}
    //队列头指针
    private transient volatile Node head;
    //队列尾指针
    private transient volatile Node tail;
    //状态位
    private volatile int state;

    //一大堆方法.....
}

3、AQS中的CLH队列
关于CLH队列,有个很有趣的地方,我以为CLH是三个英文单词的缩写,但说明里是这样写的——”CLH” (Craig, Landin, and Hagersten),应该是三个大佬的名字。
源码中的说明翻译过来就是: AQS中的等待队列是CLH阻塞队列的变种,CLH的锁常用于自旋锁。相反,我们使用它们来阻塞同步器,但使用相同的基本策略来hold住前节点(prev)的控制信息。每个节点中的“状态”字段跟踪线程是否应该被阻塞。

对于这里,我的理解是AQS中的CLH队列并没有使用自旋锁,而是用状态值来判断线程是否应该被阻塞。(如果理解错了希望广大网友可以纠正)

下面我们来分析CLH的节点类:

“`
static final class Node {
/** Marker to indicate a node is waiting in shared mode
* 表示结点处于分享模式 */
static final Node SHARED = new Node();
/** Marker to indicate a node is waiting in exclusive mode
* 表示结点处于排他模式(也有翻译成独占模式 ) */
static final Node EXCLUSIVE = null;

        //下面是几个表示状态的常量:
        /** waitStatus value to indicate thread has cancelled */
        static final int CANCELLED =  1;
        /** waitStatus value to indicate successor's thread needs unparking */
        static final int SIGNAL    = -1;
        /** waitStatus value to indicate thread is waiting on condition */
        static final int CONDITION = -2;
        /**
         * waitStatus value to indicate the next acquireShared should unconditionally propagate
         */
        static final int PROPAGATE = -3;

        /**
         * Status field, taking on only the values:
         *   SIGNAL:     此节点的后继通过park()被阻塞,当其释放或取消时,必须unpark()他的后继;
         *                为了防止冲突,获取方法必须首先指示他们需要一个信号,然后重试原子获取;
         *                在失败时,进行阻塞。这个状态就是上面提到的信号。
         *   
         *   CANCELLED:  结点被由于超时或中断被撤销,且再也无法离开这个状态;
         *   
         *   CONDITION:  结点在条件队列中,因为等待某个条件而被阻塞;它将不被用作同步队列节
         *                点,直到状态值改变为0;
         * 
         *              
         *   PROPAGATE:  大概意思是这是保证下一次可以直接传播的状态
         *   0:          除以上状态外的状态
         *
         *
         * 结点初始化时,waitStatus位为0, 要使用CAS进行修改。
         */
         volatile int waitStatus;
         //前指针 
         volatile Node prev;
         //后指针
         volatile Node next;
         //进入队列的线程
         volatile Thread thread;
         //条件队列中的下一个结点
         Node nextWaiter;

         //一大堆方法....
 }

由源码可知,CLH队列的形状大概是像下面这个样子
这里写图片描述

Java并发编程从入门到精通(三)-AQS源码分析(方法解析篇)将在不久后完笔

猜你喜欢

转载自blog.csdn.net/weixin_38278878/article/details/80040321
今日推荐