java concurrency - learning AQS

Learn AQS

A Dian AQS

   What is the AQS? Java and contracting in the abstract queue synchronizer (AbstractQueuedSchronizer), which is the basic framework in java build locks and other synchronization components such as common reentrant lock ReetrantLock, are based on the framework to achieve synchronization.

 

Two Dian understand

  The whole idea, to maintain a lock status State (int type), and a first in first out (FIFO) queue. 

  When the lock to compete, CAS will use multiple threads to modify the operating state value, if the modification is successful (success to obtain a lock), then the thread identifier for the thread to acquire the lock, if the modification fails, the thread into the end of the queue, and be blocked until the thread is awakened when the head of the queue node thread (i.e. thread acquired the lock) releases the lock, the thread will be awakened descendant node. 

   

Wed and parsing source code

   3.1) to obtain a lock

  ReentrantLock the source inlet lock () method, in the case of using a non-fair lock, call lock () method is an internal class NonFairSync.

    Final  void Lock () {
         IF (compareAndSetState (0,. 1 )) // first acquire the lock state is provided using cas 
            setExclusiveOwnerThread (Thread.currentThread ()); // If the acquisition is successful, identifying the thread acquires the lock for the current thread 
        the else 
            Acquire ( 1 ); // try to acquire the lock again, and if that fails will be added to the waiting queue 
    }    

 

  The AQS acquire () method:

    public  Final  void Acquire ( int Arg) {
         IF (! to tryAcquire (Arg) &&     // Subclasses implement to tryAcquire () method, such as fair ReentrantLock the lock, the lock unfair achieve 
            acquireQueued (addWaiter (Node.EXCLUSIVE), arg   )) // add the current thread into the wait queue, if the successor node is the first node, and then attempt to acquire the lock again 
            selfInterrupt ();   // self interrupt 
    }

  

  addWaiter AQS in () method

/**
     * Creates and enqueues node for current thread and given mode.
     *
     * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
     * @return the new node
     */
    private Node addWaiter(Node mode) {  // 两种模式, 排他模式(独占模式), 共享模式
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            if(compareAndSetTail (pred, node)) {// first attempt Direct team 
                pred.next = Node;
                 return Node; 
            } 
        } 
        ENQ (Node); // queue into the 
        return Node; 
    }

 

  enq AQS in () method

    Private the Node ENQ ( Final the Node the Node) {
         for (;;) {             // infinite loop, it uses cas been trying until it succeeds position 
            the Node t = tail;
             IF (t == null ) { // Must the initialize 
                IF (compareAndSetHead ( new new the Node ())) 
                    tail = head; 
            } the else { 
                node.prev = T;
                 IF (compareAndSetTail (T, Node)) { 
                    t.next = Node;
                     return t;
                }
            }
        }
    }

 

  acquireQueued AQS in () method

    /**
     * Acquires in exclusive uninterruptible mode for thread already in
     * queue. Used by condition wait methods as well as acquire.
     *
     * @param node the node
     * @param arg the acquire argument
     * @return {@code true} if interrupted while waiting
     */
    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
             For (;;) {// infinite loop
                 Final the Node P = node.predecessor ();
                 IF (P == head to tryAcquire && (Arg)) { // if the successor node is the head node of the current node, then try to obtain lock    
                    setHead (Node); 
                    p.next = null ; // Help the GC 
                    failed = to false ;
                     return interrupted;   
                } 
                IF (shouldParkAfterFailedAcquire (P, Node) && 
                    parkAndCheckInterrupt ()) // blocks the current thread 
                    interrupted = to true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

 

  AQS in shouldParkAfterFailedAcquire () method for determining whether should block

  private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        if (ws == Node.SIGNAL)
            /*
             * This node has already set status asking a release
             * to signal it, so it can safely park.
             */
            return true;   // condition.signal() , 请求释放锁, 说明可以安全阻塞
        if (ws > 0) {
            /*
             * Predecessor was cancelled. Skip over predecessors and
             * indicate retry.
             */
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
            /*
             * waitStatus must be 0 or PROPAGATE.  Indicate that we
             * need a signal, but don't park yet.  Caller will need to
             * retry to make sure it cannot acquire before parking.
             */
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

 

  3.2) releases the lock

  Source of inlet ReentrantLock unlock () method, the AQS actually call release () method

    /**
     * Releases in exclusive mode.  Implemented by unblocking one or
     * more threads if {@link #tryRelease} returns true.
     * This method can be used to implement method {@link Lock#unlock}.
     *
     * @param arg the release argument.  This value is conveyed to
     *        {@link #tryRelease} but is otherwise uninterpreted and
     *        can represent anything you like.
     * @return the value returned from {@link #tryRelease}
     */
    public final boolean release(intarg) {// used in the exclusive mode release
         IF (tryRelease (Arg)) {// tryRelease () method is implemented by a subclass 
            the Node H = head;
             IF ! (H = null ! = 0 && h.waitStatus ) 
                unparkSuccessor ( h); // wake successor nodes 
            return  to true ; 
        } 
        return  to false ; 
    }

  In shared mode, a corresponding method of releasing acquireShared ()

    /**
     * Acquires in shared mode, ignoring interrupts.  Implemented by
     * first invoking at least once {@link #tryAcquireShared},
     * returning on success.  Otherwise the thread is queued, possibly
     * repeatedly blocking and unblocking, invoking {@link
     * #tryAcquireShared} until success.
     *
     * @param arg the acquire argument.  This value is conveyed to
     *        {@link #tryAcquireShared} but is otherwise uninterpreted
     *        and can represent anything you like.
     */
    public final void acquireShared(int arg) {
        if (tryAcquireShared(arg) < 0)
            doAcquireShared(arg);
    }
View Code

 

  unparkSuccessor AQS in () method

/**
     * Wakes up node's successor, if one exists.
     *
     * @param node the node
     */
    private void unparkSuccessor(Node node) {
        /*
         * If status is negative (i.e., possibly needing signal) try
         * to clear in anticipation of signalling.  It is OK if this
         * fails or if status is changed by waiting thread.
         */
        int ws = node.waitStatus;
        if (ws < 0)
            compareAndSetWaitStatus(node, ws, 0);

        /*
         * Thread to unpark is held in successor, which is normally
         * just the next node.  But if cancelled or apparently null,
         * traverse backwards from tail to find the actual
         * non-cancelled successor.
         */
        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }
        if (s != null)
            LockSupport.unpark(s.thread);
    }

 

  3.3) several wait state

        / ** waitStatus value to Indicate the Thread has Canceled * / 
        static  Final  int CANCELED = 1;   // cancel 
        / ** waitStatus value Indicate by successor to the Thread's Needs unparking * / 
        static  Final  int the SIGNAL = -1;   // pointed successor node thread needs wake 
        / ** waitStatus value to indicate the thread iS oN waiting for condition condition * / 
        static  Final  int cONDITION = -2;   // pointed out that the thread is waiting for the appropriate conditions 
        / ** 
         * indicate at the waitStatus value to the Next acquireShared Should 
         * UNCONDITIONALLY the Propagate 
         * /
        static  Final  int PROPAGATE = -3;   // indicates the next acquire a shared lock requires unconditional propagation

 

  3.4) two ways of getting lock mode

        /** 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;  // 排他

 

 

 Learning materials:

  < On the java concurrent series >

  < Java concurrent Explanation of AQS >

 

 

 

Guess you like

Origin www.cnblogs.com/timfruit/p/10962821.html