Java concurrent programming from entry to proficient (2) - AQS source code analysis (composition structure)

1. What is AQS?
The full name of AQS, AbstractQueuedSynchronizer , probably means " abstract queue synchronizer ". This term is a bit abstract. Let's take a look at the introduction in the source code, lalalalala….., a long paragraph of English.

/**
 * 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.
 * */

The translation is probably:
1. AQS is a framework for implementing blocking locks and related synchronizers (semaphores, events, etc.), which is based on FIFO waiting queues;
2. AQS is "represented by a single atomic value (int)" 3. Subclasses
must define protected methods to change the state, and must also define the meaning of the state according to whether the object is acquired or released, and only through getState(), setState(), compareAndSetState( ) to update the state value.


2. Composition of 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. The CLH queue in AQS
There is a very interesting point about the CLH queue. I thought CLH was an abbreviation of three English words, but the description reads like this - "CLH" (Craig, Landin, and Hagersten), It should be the names of the three big men.
The translation of the description in the source code is: The waiting queue in AQS is a variant of the CLH blocking queue, and the CLH lock is often used for spin locks. Instead, we use them to block the synchronizer, but use the same basic strategy to hold control information from the previous node (prev). The "status" field in each node tracks whether the thread should be blocked.

For this, my understanding is that the CLH queue in AQS does not use spin locks, but uses the state value to determine whether the thread should be blocked. (If I misunderstand, I hope the majority of netizens can correct it)

Let's analyze the node class of 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
* Indicates that the node is in exclusive mode (also translated into 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;

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

As can be seen from the source code, the shape of the CLH queue is probably as follows
write picture description here

Java concurrent programming from entry to proficient (3) - AQS source code analysis (method analysis) will be completed soon

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324684098&siteId=291194637