Welcome to github.com/hsfxuebao/j… , hope to help you, if you feel ok, please click on the Star

1. The Condition definitions

Condition is a JUC utility class that allows a thread to release a lock and then wait for another thread to send a signal to wake it up. Main features:

  1. The main internal implementation of the Condition is a Condition Queue that loads the threaded Node Node
  2. Calls to Condition’s methods (await, signal, etc.) must be made if the thread has acquired an exclusive lock
  3. The Condition Queue is a unidirectional Queue (as opposed to the Sync Queue in AQS) that does not support concurrent safety, because the Condition’s methods are premised on acquiring an exclusive lock.

Let’s take a look at a common demo

import org.apache.log4j.Logger; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; Condition */ public ConditionTest {private static final Logger Logger = Logger.getLogger(ConditionTest.class); static final Lock lock = new ReentrantLock(); static final Condition condition = lock.newCondition(); public static void main(String[] args) throws Exception{ final Thread thread1 = new Thread("Thread 1 "){ @Override public void run() { lock.lock(); // Thread 1 gets lock logger.info(thread.currentThread ().getName() + "running....." ); try { Thread.sleep(2 * 1000); Logger.info (thread.currentThread ().getName() + "Stop running, wait for a signal "); condition.await(); // Call condition. Await to release the lock, encapsulate the current Node as a Node and place it in the condition Queue. Wait to wake up} catch (InterruptedException e) {e.printStackTrace(); } logger.info(thread.currentThread ().getName() + "Get a signal, continue "); lock.unlock(); // Release the lock}}; thread1.start(); Thread.sleep(1 * 1000); Thread thread2 = new Thread("Thread 2 "){ @Override public void run() { lock.lock(); // Thread 2 gets lock logger.info(thread.currentThread ().getName() + "running....." ); thread1.interrupt(); // Interrupt thread 1 to see what happens. Sleep (2 * 1000); sleep(2 * 1000); }catch (Exception e){ } condition.signal(); Sync Queue Logger.info (thread.currentThread ().getName() + "send a signal "); Logger.info (thread.currentThread ().getName() + "End of sending signal "); lock.unlock(); Thread 2 releases the lock}}; thread2.start(); }}Copy the code

The entire execution step

  1. Thread 1 starts executing, gets the lock, and then sleeps for 2 seconds
  2. When thread 1 sleeps to 1 second, thread 2 starts executing, but the lock is acquired by thread 1, so wait
  3. Thread 1 calls condition.await() after 2 seconds of sleep to release the lock and encapsulates it as a node in condition’s condition Queue, waiting for the other thread to signal. Or interrupt it (then go to Sync Queue to get the lock)
  4. Thread 1 interrupts. After thread 1 interrupts, the node is transferred from the Condition Queue to Sync Queue, but the lock is still acquired by thread 2. So the node stays in Sync Queue waiting to get the lock
  5. Thread 2 sleeps for 2 seconds and starts to wake up the nodes in the Condition Queue with signal.
  6. Thread 2 releases the lock and wakes up the node waiting to acquire the lock in Sync Queue
  7. Thread 1 is woken up to acquire the lock
  8. Thread 1 releases the lock

The execution result

[2017-02-08 22:43:09., 557] INFO Thread 1 (conditiontest.java :26) - Conditiontest.java :26..... [2017-02-08 22:43:11,565] INFO Thread 1 (conditiontest.java :30) - Conditiontest.java :30 [2017-02-08 22:43:11,565] INFO Thread 2 (conditiontest.java :48) - Thread 2 is running..... Java. Lang. InterruptedException [22:43:13 2017-02-08, 566] INFO Thread 2 (ConditionTest. Java: 57) - Thread sends a signal at 2  java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.reportInterruptAfterWait(AbstractQueuedSynchroniz Condition.java :2014) [2017-02-08 22:43:13,566] conditiontest.java :58 - ConditionTest.java:58 java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2048) [2017-02-08 22:43:13.567] INFO Thread 1 (conditiontest.java :35) - Conditiontest.java :35 Continue to perform the at com. Lami. Tuomatuo. Search. Base. The concurrent. Aqs. ConditionTest $1. The run (31) ConditionTest. Java:Copy the code

2. Constructor level basic properties

This is primarily the head and tail of the Condition Queue (which do not need to be initialized).

/** First node of condition queue */ private transient node firstWaiter; /** Last node of condition queue */ private transient node lastWaiter; ConditionObject(){return ConditionObject(){return ConditionObject(){return ConditionObject();Copy the code

3. The enqueue method addConditionWaiter

The addConditionWaiter method is used to add the current Node to the Condition Queue while calling condition. await

Note that none of the operations on the Condition Queue below take concurrency into account (Sync Queue supports concurrent operations). Why? Because Condition has acquired the exclusive lock on AQS, there is no need to worry about concurrency

/** * Adds a new waiter to wait queue to add a Node to the current thread. None of the following operations on the Condition Queue take concurrency into account (Sync Queue queues support concurrent operations). Why? * @return */ private Node addConditionWaiter(){Node t = lastWaiter; If lastWaiter is cancelled, clean out // 2. The last node has been cancelled, so it is cleared directly, // there is a problem here, 1 when t.waitStatus! . = Node CONDITION - > when to interrupt threads ConditionObject - > await - > checkInterruptWhileWaiting - > transferAfterCancelledWait "CompareAndSetWaitStatus (node, node. CONDITION, 0)" <- Cause this is normally a thread interrupt or await timeout If a Condition aWIat times out or is interrupted, the node in the Condition is not deleted and needs to be await before adding the thread to the Condition Queue by calling addConditionWaiter. Call "Node.nextwaiter! Node.nextwaiter = null if(t! = null && t.waitStatus ! = Node.CONDITION){ unlinkCancelledWaiters(); // Run the unlinkCancelledWaiters function on "waitStatus! CONDITION" (the Node inside CONDITION has a waitStatus of either CONDITION(normal), Either 0 (signal/timeout/interrupt) t = lastWaiter; Node = new Node(thread.currentThread (), node.condition); If (t == null){firstWaiter = node; Condition Queue is empty}else{t.netwaiter = node; } lastWaiter = node; // 8. Reassign lastWaiter return node; }Copy the code

4. Wake up doSignal on the first node

Wake up refers to transferring a node from the Condition Queue to Sync Queue

/** * Removes and transfers nodes until hit non-cancelled one or * null. Split out from signal in part to encourage Compilers * to inline the case of no waiters * @param first */ /** * Wakes up the head node in the Condition Queue, */ Private void doSignal(Node first){do{private void doSignal(Node first){private void doSignal(Node first){do{ if((firstWaiter = first.nextWaiter) == null){ // 1. Assign first.nextWaiter to nextWaiter to prepare for next time lastWaiter = null; If nextWaiter == null, Condition is null. If nextWaiter == null, Condition is null. // 3.first.nextwaiter == null Specifies whether a Node is changed from Condition queue to Sync queue via signal or timeout/interrupt}while(! transferForSignal(first) && (first = firstWaiter) ! = null); // Set firstWaiter to Sync Queue if first is assigned to Sync Queue.Copy the code

5. Wake up the doSignalAll method on all nodes

/** * receiving all nodes * @param first (non-null) the first node on the condition queue */ /** * transfers the condition from one side to the other */ private void doSignalAll(Node first){lastWaiter = firstWaiter = null; Do {Node next = first. NextWaiter; First. nextWaiter = null; // 2. First. NextWaiter == null Specifies whether a Node is transferred from the Condition queue to Sync queue via signal or timeout/interrupt transferForSignal(first); Call transferForSignal to transfer first to Sync Queue first = next; }while(first! = null); }Copy the code

6. Delete the unlinkCancelledWaiters method

A normal node will be woken up by the signal and moved from the Condition Queue to Sync Queue. If an interrupt or timeout is encountered, the node state will be changed directly (from Condition to 0). And put it directly into Sync without cleaning up the nodes in the Condition Queue, so we need the following function

/** * http://czj4451.iteye.com/blog/1483264 * * Unlinks cancelled waiter nodes from condition queue * Called only while holding lock. This is called when * cancellation occured during condition wait, and upon * insertion of a new waiter when lastWaiter is seen to have * been cancelled. This method is needed to avoid garbage * retention in the absence of signals. So even though it may * require a full traversal, it comes intot play when * timeouts or cancellations all nodes rather than stoppping at a * particular target to unlink All navigation to Garbege nodes * without requiring many re-traversals during cancellation */ /** AddConditionWaiter clears the Condition Queue from timeout/interrupt when the thread is added to the Queue or when the aWIAT method is almost finished This is a clever deletion that introduces the trail node, Public void unlinkCancelledWaiters(){Node t = firstWaiter; Node trail = null; while(t ! = null){ Node next = t.nextWaiter; // 1. Initialize next if(t.waitStatus! = node. CONDITION){// 2. In the Condition Queue, Node.waitStatus can only be Condition or 0(caused by timeout/interrupt). If (trail == null){// 4. No valid node is encountered once firstWaiter = next; }else{trail. NextWaiter = next; // 6. Next assigns trail.nextwaiter, If (next == null){// next == null Condition Queue lastWaiter = trail; } }else{ trail = t; // 8. Assign trail} t = next; }}Copy the code

There is no doubt that this is a very elaborate deletion of queue nodes, mainly on the trail node, which can be understood as the last valid node to traverse the entire Condition queue

7. Wake up the primary node method signal

/** * Moves the longest-waiting thread, if one exists, from the * wait queue for this condition to the wait queue for the * owning lock * * @throws IllegalMonitorStateException if {@ # link isHeldExclusively ()} * returns {@ code false} * / / * * * will Condition transferred to the head of the queue nodes */ @override public void signal() {if(! IsHeldExclusively ()) {/ / 1. Determine whether the current thread has access to an exclusive lock throw new IllegalMonitorStateException (); } Node first = firstWaiter; if(first ! = null){ doSignal(first); // 2. Call doSignal}}Copy the code

8. Wake up method signalAll on all nodes

/** * Moves all threads from the wait queue for this condition to * the wait queue for the owning lock * * @throws IllegalMonitorStateException if {@ # link isHeldExclusively ()} * return} {@ code false * / / * * * will Condition of nodes are transferred to the Queue */ public final void signalAll(){if(! isHeldExclusively()){ throw new IllegalMonitorStateException(); } Node first = firstWaiter; if(first ! = null){ doSignalAll(first); }}Copy the code

8. Release the lock and wait awaitUninterruptibly

The awaitUninterruptibly method is a method that does not respond to interrupts throughout the process

  1. Encapsulate the current thread as a Node and add it to the Condition

  2. Throw an exclusive lock owned by the current thread

  3. Wait for other threads to wake up from the Condition Queue to Sync Queue to acquire the exclusive lock

  4. After the lock is finally acquired, it is processed according to how the thread wakes up (signal/interrupt)

    / * *

    • Implements uninterruptible condition wait
    • Save lock state return by {@link #getState()}
      Copy the code
    • Invoke {@link #release(int)} with saved state as argument,
      Copy the code
    • throwing IllegalMonitoringStateException if it fails
      Copy the code
    • Block until signalled
      Copy the code
    • Reacquire by invoking specified version of
      Copy the code
    • {@link #acquire(int)} with saved state as argument
      Copy the code

    / / *

    • Await in a manner that does not respond to a thread interrupt

    */ public final void awaitUninterruptibly(){ Node node = addConditionWaiter(); Int savedState = fullyRelease(Node); // release all exclusive locks acquired by the current thread, etc. If you call the awaitUninterruptibly method you have obtained the exclusive lock Boolean interrupted = false; // 3. Thread interrupt flag while(! IsOnSyncQueue (node)){// 4. Call isOnSyncQueue to check whether the current Node has been moved to SyncQueue locksupport. park(this); // 5. If the node is not in sync queue, block the node and wait for another thread to call signal. If (thread.interrupted ()){// 6. See if this is signal or interrupted(Thread.interrupted() will know if the Thread has been interrupted, but that’s fine. If (acquireQueued(node, selfInterrupt) {} if(acquireQueued(node, selfInterrupt)}} if(acquireQueued(node, SavedState) | | interrupted) {/ / 8. AcquireQueued returns true that threads in the process of block Chinese been inetrrupt (actually acquireQueued returns true It is also possible that one of these awakenings is via signal) selfInterrupt(); If awaitUninterruptibly is interrupted, the thread outside the awaitUninterruptibly will know if the entire awaitUninterruptibly operation is interrupted}}

9. Interrupt labeling

The following two methods are used to track whether the thread has been interrupted while calling the awaitXXX method. The main difference is 1. REINTERRUPT means that the thread is interrupted after the signal (REINTERRUPT = REINTERRUPT calls selfInterrupt). Throw_IE = throw inner exception; Throw_IE = throw inner exception

/** * For interruptible waits, we need to track whether to throw * InterruptedException, if interrupted while blocked on * condition, versus reinterrupt current thread, If * interrupted while blocked waiting to re-acquire */ REINTERRUPT = re-interrupt selfInterrupt is called when the thread is interrupted. Represents those that were interrupted before receiving signal, (Throw_IE = throw inner exception) */ ** Mode meaning to reinterrupt on exit from wait */ SelfInterrupt */ private static final int REINTERRUPT = 1; /** Mode meaning to throw InterruptedException on exit from wait */ ** */ private static final int THROW_IE = -1;Copy the code

10. Interrupt handling methods

This method checks whether the wake up in awaitXX was caused by an interrupt, and if so, Node transfers

/** * Checks for interrupt, returning THROW_IE if interrupted * before signalled, REINTERRUPT if after signalled, Or * 0 if not interrupted */ ** * Signal -> locksupport. unpark * THROW_IE: This wake-up is via interrupt, and before receiving signal * REINTERRUPT: Threads of the awakening is received signal then interrupted by * / private int checkInterruptWhileWaiting (Node Node) {return Thread. Interrupted ()? (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) : 0; }Copy the code

11. ReportInterruptAfterWait

/** * Throws InterruptedException, reinterrupts current thread, or * does nothing, Depending on the mode * / / * * * this method is in awaitXX method call before you leave, is mainly based on * interrupMode judgment is an exception is thrown, */ Private void reportInterruptAfterWait(int interrupMode) throws InterruptedException{if(interrupMode == THROW_IE){ throw new InterruptedException(); } else if(interrupMode == REINTERRUPT){ selfInterrupt(); }}Copy the code

11. Method await with lock

Await this method responds to interrupt requests and, upon receipt of interrupt requests, transfers the node from the Condition Queue to Sync Queue

/** * Implements interruptible condition wait * * <li> * If current thread is interrupted, throw InterruptedException * Save lock state returned by {@link #getState()} * Invoke {@link #release(int)} with saved state as argument, * throwing IllegalMonitorStateException if it fails * Blocking until signalled or interrupted * Reacquire by invoking specifized version of * {@link #acquire(int)} with saved state as argument. * If interrupted while blocked in step 4, Throw InterruptedException * </ LI > ** @throws InterruptedException */ /** * Support the await <- of InterruptedException Note that even if the thread is interrupted, * still needs to acquire the exclusive lock, */ @override public final void await() throws InterruptedException {if(thread.interrupted ()){//  1. Throw new InterruptedException(); } Node node = addConditionWaiter(); Int savedState = fullyRelease(Node); int savedState = fullyRelease(Node); // release all locks acquired by the current thread (PS: the thread must have obtained an exclusive lock before calling the await method) int interruptMode = 0; while(! IsOnSyncQueue (node)){// 4. Check whether the current thread is in SyncQueue To move (2) the current thread is interrupted by the Node of the transfer (transfer in checkInterruptWhileWaiting)) LockSupport. Park (this); / / 5. The current thread is not in Sync Queue, to block the if ((interruptMode = checkInterruptWhileWaiting (node))! = 0) {/ / 6. Whether the thread wake up because the thread is interrupted, if be interrupted, will be in transferAfterCancelledWait checkInterruptWhileWaiting node metastasis; Returns the value interruptMode! = 0 break; }} if(acquireQueued(node, savedState) && interruptMode! If (interruptMode = REINTERRUPT){if (THROW_IE){if (interruptMode = REINTERRUPT){if (THROW_IE){if (THROW_IE){ } if(node.nextWaiter ! = null){ // clean up if cancelled // 8. Through the node nextWaiter!" Waiters() = null" The thread loves its wake up as an interrupt or signal, because the Node representing the thread at this moment has unlinkCancelledWaiters() in both the Condition Queue and Sync Queue; Cancelled nodes} if(interruptMode! = 0){ // 10. "interruptMode ! = 0" reportInterruptAfterWait(interruptMode); // 11. Depending on the type of interruptMode, decide whether to throw an exception or interrupt again}}Copy the code

12. Release the lock to wait method awaitNanos

AwaitNanos has a timeout function and the ability to respond to interrupts by moving nodes from the Condition Queue to Sync Queue regardless of the interrupt or timeout

/** * Impelemnts timed condition wait * * <li> * If current thread is interrupted, throw InterruptedException * Save lock state returned by {@link #getState()} * Invoke {@link #release(int)} with saved state as argument, * throwing IllegalMonitorStateException if it fails * Block until aignalled, interrupted, or timed out * Reacquire by invoking specified version of * {@link #acquire(int)} with saved state as argument * If Interrupted while blocked in step 4, throw InterruptedException * </li> */ ** all awaitXX methods are actually * 0. Add the current thread as a Node to the Condition * 1. The Condition Queue is awakened from the Condition Queue to Sync Queue to obtain the exclusive lock * 3. After the lock is finally fetched, processing is done according to the way the thread wakes up (signal/interrupt) * 4. */ @override public final Long awaitNanos(long nanosTimeout) throws InterruptedException { if(Thread.interrupted()){ // 1. Throw new InterruptedException(); } Node node = addConditionWaiter(); Int savedState = fullyRelease(Node); int savedState = fullyRelease(Node); Final long deadline = system.nanotime () + nanosTimeout; final long deadline = system.nanotime () + nanosTimeout; Int interruptMode = 0; while(! IsOnSyncQueue (node)){// check whether the current thread is in SyncQueue. There are two possible ways for the node to be moved from the SyncQueue to the SyncQueue To move (2) the current thread is interrupted by the Node of the transfer (transfer in checkInterruptWhileWaiting)) if (nanosTimeout < = 0, l) {/ / 6. Wait time (overtime nanosTimeout is possible here < 0), transferAfterCancelledWait (node); / / 7. Call transferAfterCancelledWait will Node from Condition to Sync Queue inside break; } if(nanosTimeout >= spinForTimeoutThreshold){ // 8. When the remaining time < spinForTimeoutThreshold, the spin function is actually more efficient than locksupport. parkNanos locksupport. parkNanos(this, nanosTimeout); / / 9. Thread block} the if ((interruptMode = checkInterruptWhileWaiting (node))! = 0) {/ / 10. Determine whether the thread wakes up because the thread is interrupted, if be interrupted, will be in transferAfterCancelledWait checkInterruptWhileWaiting node metastasis; Returns the value interruptMode! = 0 break; } nanosTimeout = deadline-system.nanotime (); If (acquireQueued(node, savedState) && interruptMode! If (interruptMode = REINTERRUPT; if (THROW_IE){// 12. Use the acquireQueued command to obtain the exclusive lock in the Sync Queue. } if(node.nextWaiter ! = null){// 13. Pass "Node.nextwaiter! Waiters() = null" The thread loves its wake up as an interrupt or signal, because the Node representing the thread at this moment has unlinkCancelledWaiters() in both the Condition Queue and Sync Queue; Cancelled nodes} if(interruptMode! = 0){ // 15. "interruptMode ! = 0" reportInterruptAfterWait(interruptMode); Return deadline-system.nanotime (); // 16. Determine whether to throw an exception or interrupt again based on interruptMode's type. // 17 this returns a signal or timeout}Copy the code

13. Release the lock and wait until

/** * Implements absolute timed condition wait * <li> * If current thread is interrupted, throw InterruptedException * Save lock state returned by {@link #getState()} * Invoke {@link #release(int)} with saved state as argument, * throwing IllegalMonitorStateException if it fails * Block until signalled, interrupted, or timed out * Reacquire by invoking specialized version of * {@link #acquire(int)} with saved state as argument * if interrupted while blocked in step 4, throw InterruptedException * If timeed out while blocked in step 4, return false, Else true * </li> */ ** * All awaitXX methods are actually * 0. Add the current thread as a Node to the Condition * 1. The Condition Queue is awakened from the Condition Queue to Sync Queue to obtain the exclusive lock * 3. After the lock is finally fetched, processing is done according to the way the thread wakes up (signal/interrupt) * 4. * * awaitUntil is the same as awaitNanos */ @override public Boolean awaitUntil(Date deadline) throws  InterruptedException { long abstime = deadline.getTime(); If (thread.interrupted ()){throw new InterruptedException(); } Node node = addConditionWaiter(); Int savedState = fullyRelease(Node); int savedState = fullyRelease(Node); // 3. Release all locks acquired by the current thread (PS: to call await method, the current thread must have acquired exclusive lock) Boolean timeout = false; int interruptMode = 0; while(! IsOnSyncQueue (node)){// 4. Check whether the current thread is in SyncQueue To move (2) the current thread is interrupted by the Node of the transfer (transfer in checkInterruptWhileWaiting)) if (System. CurrentTimeMillis () > abstime) {/ / 5. Calculate whether the timeout timeout = transferAfterCancelledWait (node); / / 6. Will call transferAfterCancelledWait Node from Condition to Sync Queue inside break; } LockSupport.parkUntil(this, abstime); / / 7. Thread blocking the if ((interruptMode = checkInterruptWhileWaiting (node))! = 0) {/ / 8. Determine whether the thread wakes up because the thread is interrupted, if be interrupted, will be in transferAfterCancelledWait checkInterruptWhileWaiting node metastasis; Returns the value interruptMode! = 0 break; }} if(acquireQueued(node, savedState) && interruptMode! If (interruptMode = REINTERRUPT){if (THROW_IE){if (interruptMode = REINTERRUPT){if (THROW_IE){ } if(node.nextWaiter ! = null){// 10. Pass "Node.nextwaiter! Waiters() = null" The thread loves its wake up as an interrupt or signal, because the Node representing the thread at this moment has unlinkCancelledWaiters() in both the Condition Queue and Sync Queue; Cancelled nodes} if(interruptMode! = 0){ // 12. "interruptMode ! = 0" reportInterruptAfterWait(interruptMode); // 13. Depending on the type of interruptMode, whether to throw an exception or interrupt again} return! timeout; // 13. Returns whether threads are awakened with interrupt}Copy the code

14. The instrumentation method

Returns true if this condition was created by the given * synchronization object */ final boolean isOwnedBy(KAbstractOwnableSynchronizer sync){ return sync == KAbstractQueuedSynchronizer.this; } /** * Quires whether any threads are waiting on this condition * Implements {@link KAbstractOwnableSynchronizer#"hasWaiters(ConditionObject)} * * @return {@code true} if there are any waiting threads * @ throws IllegalMonitorStateException if {@ # link isHeldExclusively ()} * returns {@ code false} * * * * / / to check the Condition of the Queue */ protected final Boolean hasWaiters(){if(! isHeldExclusively()){ throw new IllegalMonitorStateException(); } for(Node w = firstWaiter; w ! = null; w = w.nextWaiter ){ if(w.waitStatus == Node.CONDITION){ return true; } } return false; } /** * Returns an estimate of the number of threads waiting on * this condition * Implements {@link KAbstractOwnableSynchronizer#"getWaitQueueLength()} * * @return the estimated number of waiting threads * @throws IllegalMonitorStateException if {@ # link isHeldExclusively ()} * return} {@ code false * * * * / / access Condition in the queue */ protected final int getWaitQueueLength(){if(! isHeldExclusively()){ throw new IllegalMonitorStateException(); } int n = 0; for(Node w = firstWaiter; w ! = null; w = w.nextWaiter){ if(w.waitStatus == Node.CONDITION){ ++n; } } return n; } /** * Returns a collection containing those threads that may be * waiting on this Condition * Implements {@link KAbstractOwnableSynchronizer#'getWaitingThreads} * * @return the collection of thread * @throws IllegalMonitorStateException if {@ # link isHeldExclusively ()} * returns {@ code false} * * * * / / threads that are waiting to get * / protected final Collection<Thread> getWaitingThreads(){ if(! isHeldExclusively()){ throw new IllegalMonitorStateException(); } ArrayList<Thread> list = new ArrayList<>(); for(Node w = firstWaiter; w ! = null; w = w.nextWaiter){ if(w.waitStatus == Node.CONDITION){ Thread t = w.thread; if(t ! = null){ list.add(t); } } } return list; }Copy the code

15 summary

The Condition class provides a basic way to mediate locks between threads, but Condition still requires a lock. In the analysis of the code involves a large number of AQS method in a class if I don’t know please click AbstractQueuedSynchronizer

Reference:

Condition source code analysis (based on Java 8) Condition source study notes 1.6 AbstractQueuedSynchronizer AbstractQueuedSynchronizer introduction and the analysis of principle of Java source code parsing Jdk1.6 JUC source code parsing (6) – the locks – AbstractQueuedSynchronizer JUC JDK1.8 source analysis of AbstractQueuedSynchronizer (2) Java concurrency locks ReentrantReadWriteLock AbstractQueuedSynchronizer read-write lock source code analysis