当前位置:网站首页>Analysis of reentrantlock source code of AQS

Analysis of reentrantlock source code of AQS

2022-06-09 05:14:00 smartjiang-java

1:AQS Basic knowledge of

AQS, The full name is AbstractQueuedSynchronizer , abstract class , It is the framework of blocking lock and related synchronizer tools . Has the following characteristics :

 1.  use  state  Property to represent the state of the resource ( It can be divided into exclusive mode and shared mode ), Subclasses need to define how to maintain this state , Controls how locks are acquired and released 
      1. getState -  obtain  state  state 
      2. setState -  Set up  state  state 
      3. compareAndSetState - cas  Mechanism settings  state  state 
      4.  Exclusive mode is that only one thread can access the resource , Shared mode allows multiple threads to access resources 
   2.  Provides the basis for  FIFO  Waiting queue , Be similar to  Monitor  Of  EntryList
   3.  Conditional variables to achieve waiting 、 Wake up mechanism , Support multiple conditional variables , Be similar to  Monitor  Of  WaitSet

Subclasses mainly need to implement AQS Here are some ways , Default throw UnsupportedOperationException

  1. tryAcquire
  2. tryRelease
  3. tryAcquireShared
  4. tryReleaseShared
  5. isHeldExclusively

2: Lock principle

because ReentrantLock Two synchronizers are provided , Achieve fair lock FairSync And unfair lock NonfairSync , Default is unfair lock .

2.1: Not fair lock NonfairSync

2.1.1: Lock principle

Suppose there are only thread-0 Thread to lock , So enter lock() Method

    static final class NonfairSync extends Sync {
    
        private static final long serialVersionUID = 7316153563782823691L;
    
        final void lock() {
    
        //  Come here first through  cas  Try to  state  The value of is determined by  0  become  1 : Modification successful , Set the owner of the lock to  thread-0
        //  thus it can be seen , The first incoming thread only needs to try once to acquire the lock successfully , Locking success 
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
    
            return nonfairTryAcquire(acquires);
        }
    }

Here comes again thread-1 Threads , Also go to lock() Method

    static final class NonfairSync extends Sync {
    
        private static final long serialVersionUID = 7316153563782823691L;
    
        final void lock() {
    
        //  Come here first through  cas  Try to  state  The value of is determined by  0  become  1 , So because  state  The value of has been  thread-0  It has been modified into  1 ,
        //  So the attempt to replace here is bound to fail , Enter into  acquire(1); 
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
    
            return nonfairTryAcquire(acquires);
        }
    }

Get into acquire(1) Method

    public final void acquire(int arg) {
    
    //  Try calling  tryAcquire() Method , Get the lock again , This is the second acquisition 
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

Enter into tryAcquire(1) Method , find NonfairSync Implementation method

    static final class NonfairSync extends Sync {
    
        private static final long serialVersionUID = 7316153563782823691L;
        
        final void lock() {
    
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
       
       //  Go to this method , And then call  nonfairTryAcquire(1)
        protected final boolean tryAcquire(int acquires) {
    
            return nonfairTryAcquire(acquires);
        }
    }

Enter into nonfairTryAcquire(1) Method

        final boolean nonfairTryAcquire(int acquires) {
    
            final Thread current = Thread.currentThread();
            int c = getState();
            //  Judge again  state  Is it  0, If it is 0, Then pass again cas  Attempt to acquire lock . This is obviously not the place to go 
            if (c == 0) {
    
                if (compareAndSetState(0, acquires)) {
    
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
           // state  Not for 0, This indicates that a thread has been locked , Determine whether the locking thread is the current thread , Lock reentry ,state  Add  1 . Obviously not here 
            else if (current == getExclusiveOwnerThread()) {
    
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            //  Come here , Return here  false 
            return false;
        }

Back to acquire(1) Method

    public final void acquire(int arg) {
    
    // tryAcquire(1)  return fasle, !tryAcquire(arg)  Namely  true , Enter into  addWaiter(Node.EXCLUSIVE) Method 
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

Get into addWaiter(Node.EXCLUSIVE) Method

    private Node addWaiter(Node mode) {
    
        //  A new node is created for the current thread  node 
        Node node = new Node(Thread.currentThread(), mode);
        Node pred = tail;
        //  Judge  AQS  If the end node of the waiting queue of is not  null, Then put the new  node  Node passing  cas  Set as tail node , And back to .
        //  obviously , We haven't let the thread go in the waiting queue yet , Then the beginning and end nodes of the queue are  null,  Obviously not here 
        if (pred != null) {
    
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
    
                pred.next = node;
                return node;
            }
        }
        //  Enter into  enq(node)  Method 
        enq(node);
        return node;
    }
    }

Enter into enq(node) Method

    private Node enq(final Node node) {
    
    //  Here we enter the cycle operation 
        for (;;) {
    
            Node t = tail;
            //  First cycle after entering , If the tail node is  null,  that   Create a   New nodes , We call it a subatomic node , adopt  cas  Replace with the head node 
            //  hold   The sub element node is set as the tail node . At this time, the sub element node is both the head node and the tail node  
            if (t == null) {
     
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
    
            //  The second cycle , The tail node is a sub element node  , No  null, Try to use  cas  hold  node  The node is set as the tail node .
            //  here , The head node is a sub element node , No node is  node  node , Out of the loop .
                node.prev = t;
                if (compareAndSetTail(t, node)) {
    
                    t.next = node;
                    return t;
                }
            }
        }
    }

Back to addWaiter(Node.EXCLUSIVE) Method

    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);
        //  Returns... Based on the node created by the current thread 
        return node;
    }
    }

Get into acquire(1) Method

    public final void acquire(int arg) {
    
        if (!tryAcquire(arg) &&
            //  Enter into  acquireQueued(node,1)  Method 
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

Enter into acquireQueued(node,1) Method

    final boolean acquireQueued(final Node node, int arg) {
    
        boolean failed = true;
        try {
    
            boolean interrupted = false;
            //  Enter the loop 
            for (;;) {
    
                //  find  node  The previous node of the node , This we know is a sub - element node  p 
                final Node p = node.predecessor();
                //  If  p  Head node , that   The current thread attempts to acquire the lock again , The third attempt to acquire the lock . It must have been a failure 
                if (p == head && tryAcquire(arg)) {
    
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                //  Enter into  shouldParkAfterFailedAcquire(p,node)  Method 
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
    
            if (failed)
                cancelAcquire(node);
        }
    }

Enter into shouldParkAfterFailedAcquire(p,node) Method

    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    
    //  Get the initialized state value of the sub element node  0 
        int ws = pred.waitStatus;
        //  Judge whether the value is  -1, Obviously not , be equal to  0 
        if (ws == Node.SIGNAL)
            return true;
        if (ws > 0) {
    
            do {
    
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
    
            //  Try to use  cas  Set the state value of the sub - element node from  0  become  -1
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        //  return  false
        return false;
    }

go back to acquireQueued(node,1) Method

 final boolean acquireQueued(final Node node, int arg) {
    
        boolean failed = true;
        try {
    
            boolean interrupted = false;
            //  Enter the loop 
            for (;;) {
    
                //  The second cycle : find  node  The previous node of the node , This we know is a sub - element node  p 
                final Node p = node.predecessor();
                //  If  p  Head node , that   The current thread attempts to acquire the lock again , The fourth attempt to acquire the lock . It must have been a failure 
                if (p == head && tryAcquire(arg)) {
    
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                // shouldParkAfterFailedAcquire(p, node)  Return to  false, Enter the second loop 
                //  The second cycle goes into  shouldParkAfterFailedAcquire(p, node)  Method 
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
    
            if (failed)
                cancelAcquire(node);
        }
    }

Enter into shouldParkAfterFailedAcquire(p, node) Method

    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    
    //  Get the sub element node state value  -1
        int ws = pred.waitStatus;
        //  Judge whether the value is  -1, Obviously , return  true
        if (ws == Node.SIGNAL)
            return true;
        if (ws > 0) {
    
            do {
    
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
    
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

go back to acquireQueued(node,1) Method

 final boolean acquireQueued(final Node node, int arg) {
    
        boolean failed = true;
        try {
    
            boolean interrupted = false;
            for (;;) {
    
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
    
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                // shouldParkAfterFailedAcquire(p, node)  Return to  true, Get into  parkAndCheckInterrupt()  Method 
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
    
            if (failed)
                cancelAcquire(node);
        }
    }

Get into parkAndCheckInterrupt() Method

    private final boolean parkAndCheckInterrupt() {
    
        //  Block the current thread , And clear the break mark 
        LockSupport.park(this);
        return Thread.interrupted();
    }

go back to acquireQueued(node,1) Method

 final boolean acquireQueued(final Node node, int arg) {
    
        boolean failed = true;
        try {
    
            boolean interrupted = false;
            for (;;) {
    
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
    
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                // shouldParkAfterFailedAcquire(p, node)  Return to  true,parkAndCheckInterrupt() Return to  true,
                //  The thread is blocked , If the middle is interrupted , that  interrupted  by  true, Just set the break flag to true, No other operation .
                //  Will still reside in AQS In line , Wait for the lock to be acquired before continuing operation ( Continue operation , The break mark is marked as  true)
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
    
            if (failed)
                cancelAcquire(node);
        }
    }

Here comes again thread-2 Threads , Also go to lock() Method

    static final class NonfairSync extends Sync {
    
        private static final long serialVersionUID = 7316153563782823691L;
    
        final void lock() {
    
        //  Come here first through  cas  Try to  state  The value of is determined by  0  become  1 , So because  state  The value of has been  thread-0  It has been modified into  1 ,
        //  So the attempt to replace here is bound to fail , Enter into  acquire(1); 
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
    
            return nonfairTryAcquire(acquires);
        }
    }

Get into acquire(1) Method

    public final void acquire(int arg) {
    
    //  Try calling  tryAcquire() Method , Get the lock again , This is the second acquisition 
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

Enter into tryAcquire(1) Method , find NonfairSync Implementation method

    static final class NonfairSync extends Sync {
    
        private static final long serialVersionUID = 7316153563782823691L;
        
        final void lock() {
    
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
       
       //  Go to this method , And then call  nonfairTryAcquire(1)
        protected final boolean tryAcquire(int acquires) {
    
            return nonfairTryAcquire(acquires);
        }
    }

Enter into nonfairTryAcquire(1) Method

        final boolean nonfairTryAcquire(int acquires) {
    
            final Thread current = Thread.currentThread();
            int c = getState();
            //  Judge again  state  Is it  0, If it is 0, Then pass again cas  Attempt to acquire lock . This is obviously not the place to go 
            if (c == 0) {
    
                if (compareAndSetState(0, acquires)) {
    
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
           // state  Not for 0, This indicates that a thread has been locked , Determine whether the locking thread is the current thread , Lock reentry ,state  Add  1 . Obviously not here 
            else if (current == getExclusiveOwnerThread()) {
    
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            //  Come here , Return here  false 
            return false;
        }

Back to acquire(1) Method

    public final void acquire(int arg) {
    
    // tryAcquire(1)  return fasle, !tryAcquire(arg)  Namely  true , Enter into  addWaiter(Node.EXCLUSIVE) Method 
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
    private Node addWaiter(Node mode) {
    
        //  A new node is created for the current thread  node 
        Node node = new Node(Thread.currentThread(), mode);
        Node pred = tail;
        //  Judge  AQS  If the end node of the waiting queue of is not  null, Then put the new  node  Node passing  cas  Set as tail node , And back to .
        //  obviously , The tail node is  thread-1, No  null, Replacement successful , return  node
        if (pred != null) {
    
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
    
                pred.next = node;
                return node;
            }
        }
        //  Enter into  enq(node)  Method 
        enq(node);
        return node;
    }
    }

Back to acquire(1) Method , It's almost the same later , Change the state of the previous node of the node from 0 become -1, And block , Interrupt tasks

    public final void acquire(int arg) {
    
    //  Enter into acquireQueued(node, 1)  Method 
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

2.1.1: Unlock the principle

When the thread occupying the lock completes its work , call unLock() Method

    public void unlock() {
    
    //  Calling the synchronizer  release()  Method 
        sync.release(1);
    }

Calling the synchronizer release(1) Method

    public final boolean release(int arg) {
    
    //  Get into  tryRelease(1)  Method 
        if (tryRelease(arg)) {
    
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

Get into tryRelease(1) Method

        protected final boolean tryRelease(int releases) {
    
            // state -1 
            int c = getState() - releases;
            //  If the current thread is not a locked thread , Throw an exception 
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            //  If  state -1  be equal to  0 , that   The lock identification is set to  null , return  true
            if (c == 0) {
    
                free = true;
                setExclusiveOwnerThread(null);
            }
            //  This is based on  state  To determine the reentry of the lock , If re entered by the lock , There is only one layer of solution here , It needs to be solved several times 
            setState(c);
            return free;
        }

Back to the synchronizer release(1) Method

    public final boolean release(int arg) {
    
    // tryRelease(1)  return  true, unlocked 
        if (tryRelease(arg)) {
    
            Node h = head;
            //  Determine whether the head node of the waiting queue is not  null, also  state  The value is not  0 , We know it is  -1 , Enter into  unparkSuccessor(h)  Method 
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

Enter into unparkSuccessor(h) Method

 private void unparkSuccessor(Node node) {
    
        int ws = node.waitStatus;
        //  Judge the head node ( Yayuan ) The state of , cas  Set first as  0 
        if (ws < 0)
            compareAndSetWaitStatus(node, ws, 0);
        //  Find the next node after the head node , waitStatus  yes  -1  No  0 
        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 the following node of the head node is not  null, Wake up the first thread behind the header node 
        if (s != null)
            LockSupport.unpark(s.thread);
    }

If there is no new thread to compete with , that thread-1 go back to acquireQueued(node,1) Method

 final boolean acquireQueued(final Node node, int arg) {
    
        boolean failed = true;
        try {
    
            boolean interrupted = false;
            for (;;) {
    
                //  find  thread-1  The previous node of 
                final Node p = node.predecessor();
                //  If the previous node is head node , Then let  thread-1  Try competing locks , If successful ,
                //  take  thread-1 The node   Set as head node 
                if (p == head && tryAcquire(arg)) {
    
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
    
            if (failed)
                cancelAcquire(node);
        }
    }

2.1: Fair lock FairSync

Not fair lock : When trying to acquire the lock , Direct use cas Competitive lock , Don't check AQS queue
Fair lock : When trying to acquire the lock , Check it out first AQS Whether there are waiting threads in the queue , If not, just compete ; Some words . Go into the waiting queue

Fair lock :

    static final class FairSync extends Sync {
    
        private static final long serialVersionUID = -3000897897090466540L;

        final void lock() {
    
            acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
    
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
    
              //  First, check whether there is a precursor node in the waiting queue , No more competition . If there is , Enter the waiting queue 
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
    
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
    
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    }

Not fair lock :

        final boolean nonfairTryAcquire(int acquires) {
    
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
    
            //  Try to use  cas  Get the lock , No inspection  AQS  queue , Reflects the unfairness 
                if (compareAndSetState(0, acquires)) {
    
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
    
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

3: Interrupted principle

ReentrantLock The default is non interruptible , Interruptible needs to call lockInterruptibly() Method

    public void lockInterruptibly() throws InterruptedException {
    
        //  Get into  acquireInterruptibly(1)  Method 
        sync.acquireInterruptibly(1);
    }

Get into acquireInterruptibly(1) Method

    public final void acquireInterruptibly(int arg)
            throws InterruptedException {
    
        if (Thread.interrupted())
            throw new InterruptedException();
        //  If you don't get the lock , Interruptible locking process , Enter into  doAcquireInterruptibly(1)  Method 
        if (!tryAcquire(arg))
            doAcquireInterruptibly(arg);
    }

Enter into doAcquireInterruptibly(1) Method

    private void doAcquireInterruptibly(int arg)
        throws InterruptedException {
    
        //  Judge  AQS  If the end node of the waiting queue of is not  null, Then put the new  node  Node passing  cas  Set as tail node , And back to .
        //  If it is the first queue element , The head node is a sub element node . This has been analyzed before 
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
    
            for (;;) {
    
            //  Get the previous node of the current node 
                final Node p = node.predecessor();
                //  Determine whether the previous node is a header node , Then try to get the lock 
                if (p == head && tryAcquire(arg)) {
    
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
                //  The current thread is blocked , But if it is interrupted during blocking , Throw an exception .
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    throw new InterruptedException();
            }
        } finally {
    
            if (failed)
                cancelAcquire(node);
        }
    }

4: The principle of conditional variable implementation

4.1: Create conditional variables

newCondition() Method , The return value is Condition object , yes AQS The inner class of

    public Condition newCondition() {
    
        return sync.newCondition();
    }
        final ConditionObject newCondition() {
    
            return new ConditionObject();
        }

so : Each condition variable actually corresponds to a waiting queue , The implementation class is ConditionObject Maintain a two-way linked list , As not meeting the conditions , Where the threads rest

4.2: Variables that do not satisfy the condition

        public final void await() throws InterruptedException {
    
           //  If interrupted , Throw an exception 
            if (Thread.interrupted())
                throw new InterruptedException();
            //  Add the current thread to  Condition  Waiting queue  , New node's  waitStatus  Set to  -2, Returns the current node  
            Node node = addConditionWaiter();
            //  Release the lock held by the current thread , Wake up the second node after the head node in the waiting queue to compete for the lock 
            int savedState = fullyRelease(node);
            int interruptMode = 0;
            //  If the node's  state  be equal to -2  Or the precursor node is  null , that  park  live , At this point, the thread is  park  live 
            while (!isOnSyncQueue(node)) {
    
                LockSupport.park(this);
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
            }
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                interruptMode = REINTERRUPT;
            if (node.nextWaiter != null) // clean up if cancelled
                unlinkCancelledWaiters();
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
        }

4.3: Satisfy conditional variables

 public final void signal() {
    
            //  Determine whether the current node is the lock holder , If not, throw an exception 
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            // Find the first node in the condition variable , And wake up 
            Node first = firstWaiter;
            if (first != null)
                doSignal(first);
        }

Enter into doSignal() Method

        private void doSignal(Node first) {
    
            do {
    
             // If the next node of the head node is null, Then the linked list header node is set to null
                if ( (firstWaiter = first.nextWaiter) == null)
                    lastWaiter = null;
                first.nextWaiter = null;
                //ps: Here is the transfer node , The possibility of failure : Be interrupted , Timeout etc. 
            } while (!transferForSignal(first) &&
                     (first = firstWaiter) != null);
        }

Enter into transferForSignal() Method

    final boolean transferForSignal(Node node) {
    
       // use cas Try to change the state of the node from  -2  become  0
        if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
            return false;
        // Put the node in  AQS  End of queue , Return the original tail node to 
        Node p = enq(node);
        int ws = p.waitStatus;
        // Return the status of the node through cas from  0  become  -1, Make it qualified to wake up 
        if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
            LockSupport.unpark(node.thread);
        return true;
    }
原网站

版权声明
本文为[smartjiang-java]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/160/202206090511358020.html