Analytical AQS source (1) -CLH

AQS resolve

I. Introduction

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 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 int value manipulated using methods getState(), setState(int) and compareAndSetState(int, int) is tracked with respect to synchronization.

AQS implemented using a synchronous queue FIFO provides the basic framework for the associated lock and synchronization lock. It integer representation of a state in order to provide a basic skeleton can be used are synchronizers. By AQS subclass method in protected rewritten so as to realize free and acquire the lock, through this form sub-class will be able to have a complete team and into the locking mechanism.

AQS theory used in synchronous FIFO queue implemented had raised from CLH, that will AQS is talking about the basic implementation of CLH

The wait queue is a variant of a "CLH" (Craig, Landin, and* Hagersten) lock queue. CLH locks are normally used for* spinlocks.

Second, the basic attributes and state synchronization

static final class Node {
    /** 共享模式 */
    static final Node SHARED = new Node();
    /** 独占模式 */
    static final Node EXCLUSIVE = null;

    /** 标明当前线程已经被取消 */
    static final int CANCELLED =  1;
    /** 线程的下一个等待线程需要被唤醒 */
    static final int SIGNAL    = -1;
    /** 当前线程正在等待中 */
    static final int CONDITION = -2;
    /** 下一次的acquire方法应该被无条件的传播*/
    static final int PROPAGATE = -3;

    /** 当前等待状态*/
    volatile int waitStatus;

    /** 前驱节点*/
    volatile Node prev;

    /** 与上面类似         */
    volatile Node next;

    /** 当前node持有的线程,在构造器中初始化,在退出队列后被置为null*/
    volatile Thread thread;

    /** 指向当前节点的后面第一个处于CODITION状态的节点,或者为SHARED,只有对于独占式才会有CODTION节点的存         *在,对于共享式的其nextWaiter为SHARED(变量)
         */
    Node nextWaiter;

    /**
         * Returns true if node is waiting in shared mode.
         */
    final boolean isShared() {
        return nextWaiter == SHARED;
    }

    /** 返回前驱节点,添加一层封装*/
    final Node predecessor() throws NullPointerException {
        Node p = prev;
        if (p == null)
            throw new NullPointerException();
        else
            return p;
    }

    Node() {    // 用于创建出事头结点和SHARED标志的构造器
    }

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

** synchronization state is divided into five kinds, 0 INITIAL, 1 CANCELLED, -1 SINGAL, -2 CONDITION, -3 of PROPAGETE**the role and status information following five states

  • SIGNAL: successor node of the node has passed the LockSupport.part()method blocks the current node is released or is deleted after its successor nodes need to wake up, to avoid competition between threads, access to resources acquireall methods should be set SIGNALflag, then re atomic capturing operation, if the acquisition fails, blocked
  • CANCELLED: node due to timeout or interruption into the CANCELLEDstate, the node if the state will not enter into other states, the state of the thread will not be blocked
  • CONDITION: the node is waiting in the queue, he will use as an ordinary node of the synchronization queue (i.e., not be awakened or precursor node unpark()), unless he's state is set to 0INITIAL
  • PROPAGETE: releasing the shared lock ( releaseShared) should be passed to other nodes. In doReleaseSharedthe first node is used to ensure the dissemination of information will continue
  • INITIAL: initial state or intermediate state

These types of states can be distinguished by a more simple: If >0that is CANCELLED, <=0the state that can be used

CLH synchronous queue, the following chart

123

  • prev predecessor node to node, next node is node rear-wheel drive

nextWaiterField, saving a mode-locked state (Mode), tryAcquire(int)and a tryAcquireShared(int)method of obtaining state by exclusive or shared mode, if it fails to call addWaiter (Node mode) way into the team. nextWaiter is used to indicate that the current form

  • SHARED enumeration sharing mode, the value of new Node (), the values are unique, using staticmodified
  • EXCLUSIVE enumeration exclusive mode, the value ofnull

#predecessor()Way, a Node node before a Node node. In the interior of the method, Node p = prevthe local copy is to avoid the concurrency, prevjudged complete == nullwhen happens to be modified, in order to ensure thread safety.

Third, the team addWaiter

3.1 Introduction The basic steps

  1. Generate a new nodenode
  2. The new node nodeprecursor tail node points to the originaltail4324

    1. UNSAFE provided by the tail node tailto the new nodenode4234241

    2. Provided penultimate node is tail node of the original old tailrear-drive node nextis tail node newnode423423

  3. If it fails by enqretry again
    1. If the first node is null, a new node nodeis provided to the head node
    2. No performs an operation similar to Step 2

Use graphical form to describe the team's problems

3.2 addWaiter()

Deep into the addWaiter()source code view

private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
        // 先进行一次简单的入队尝试
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        enq(node);
        return node;
    }

3.3 enq (Node node)

enqMethods and methods addWaiterconsistent , the main difference is that when considering the node does not need to initialize the current node is set to node initializationhead node

private Node enq(final Node node) {
    for (;;) {
        Node t = tail;
        if (t == null) { // 如果头部不存在就进行初始化
            if (compareAndSetHead(new Node()))
                tail = head;
        } else {
            node.prev = t;//该步骤和3.2中的步骤类似
            if (compareAndSetTail(t, node)) {
                t.next = node;
                return t;
            }
        }
    }
}

Fourth, the team

CLH synchronization queue to follow the FIFO, the thread releases the synchronization status of the first node, it will wake up the next node ( Node.next). The successor node will be successful in obtaining synchronization status, set itself a head node ( head).

This process is very simple, headthe implementation of the original node and disconnect the first node nextand the current node prevcan be. Note that in this process is the need to use CAS to ensure that , because only one thread can successfully get into sync.

Procedure is as follows:

#setHead(Node node)Methods to achieve the above-described dequeue logic. code show as below:

private void setHead(Node node) {   
    head = node;    node.thread = null;    node.prev = null;
                                }

reference

Guess you like

Origin www.cnblogs.com/Heliner/p/11575224.html