1. An overview of the

1.1 introduction

Java Condition use and analysis

  • Condition variables are implemented in Java. Java util. Concurrent. The locks. Condition interfaces, Condition variables, the Lock object is instantiated by a call newCondition () method to get, such conditions as a Lock object binding up. Condition variables in Java can only be used in conjunction with locks to control the security of concurrent programs accessing competing resources. [Condition variables and locks need to be used together]

  • Condition appears in Java 1.5 as an alternative to the traditional Wait () and notify() of an Object to implement inter-thread collaboration (wait () and notify() are less elaborate). It is safer and more efficient to implement inter-thread collaboration using await() and signal() of the Condition. Condition is therefore generally recommended, and blocking queues actually use Condition to simulate inter-thread collaboration.

  • Condition is a multithreaded communication tool that causes one or several threads to wait for a Condition (Condition), and only when the Condition is met (signal or signalAll is called) will the waiting threads wake up and re-compete for the lock.

  • Condition is an interface, and the basic methods are await() and signal() methods;

    • Condition depends on the Lock interface. The basic code to generate a Condition is lock.newCondition().

Calls to the await() and signal() methods of the Condition must be within the lock protection, that is, between lock.lock() and lock.unlock

    • Await () in Conditon corresponds to wait() of Object;
    • Signal () in Condition corresponds to the notify() of Object;
    • SignalAll () in the Condition corresponds to notifyAll() of the Object.

Example 2.

2.1 Through the signal itself to achieve the sequential loop execution method

Our own implementation is executed by means of signals: execute a(), then execute b(), and then execute c() in the order of execution.

Public class SignalThread {private int mySignal; public class SignalThread {private int mySignal; public synchronized void first() { while (mySignal ! = 0) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("first"); mySignal++; notifyAll(); } public synchronized void second() { while (mySignal ! = 1) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("second"); mySignal++; notifyAll(); } public synchronized void third() { while (mySignal ! = 2) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("third"); mySignal = 0; notifyAll(); } public static void main(String[] args) { SignalThread d = new SignalThread(); A a = new A(d); B b = new B(d); C c = new C(d); new Thread(a).start(); new Thread(b).start(); new Thread(c).start(); } } class A implements Runnable { private SignalThread signalThread; public A(SignalThread signalThread) { this.signalThread = signalThread; } @Override public void run() { while (true) { signalThread.first(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } class B implements Runnable { private SignalThread signalThread; public B(SignalThread signalThread) { this.signalThread = signalThread; } @Override public void run() { while (true) { signalThread.second(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } class C implements Runnable { private SignalThread signalThread; public C(SignalThread signalThread) { this.signalThread = signalThread; } @Override public void run() { while (true) { signalThread.third(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }}}}Copy the code

2.2 Condition loops through methods in order

Condition is used to implement multiple methods in order.

public class ConditionThread { Lock lock = new ReentrantLock(); Condition firstCondition = lock.newCondition(); Condition secondCondition = lock.newCondition(); Condition thirdCondition = lock.newCondition(); public void first() { lock.lock(); try { firstCondition.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("firstCondition"); secondCondition.signal(); lock.unlock(); } public void second() { lock.lock(); try { secondCondition.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("secondCondition"); thirdCondition.signal(); lock.unlock(); } public void third() { lock.lock(); try { thirdCondition.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("thirdCondition"); firstCondition.signal(); lock.unlock(); } public static void main(String[] args) { ConditionThread conditionThread = new ConditionThread(); A a = new A(conditionThread); B b = new B(conditionThread); C c = new C(conditionThread); new Thread(a).start(); new Thread(b).start(); new Thread(c).start(); } } class A implements Runnable { private ConditionThread conditionThread; public A(ConditionThread conditionThread) { this.conditionThread = conditionThread; } @Override public void run() { while(true) { conditionThread.first(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } class B implements Runnable { private ConditionThread conditionThread; public B(ConditionThread conditionThread) { this.conditionThread = conditionThread; } @Override public void run() { while(true) { conditionThread.second(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } class C implements Runnable { private ConditionThread conditionThread; public C(ConditionThread conditionThread) { this.conditionThread = conditionThread; } @Override public void run() { while(true) { conditionThread.third(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }}}}Copy the code

3. Source analysis

  • The Condition interface contains multiple await methods and two notification methods. Because wait is an Object method, the new name is await.

  • ConditionObject realized Condition interfaces, is AbstractQueuedSynchronizer inner classes

  • Reentrantlock’s newCondition method returns the Condition object associated with a lock instance

  • We see that the condition implementation depends on AQS, which is an abstract class. It defines the basic framework of the synchronizer, the realization of the basic structure function. Maintenance of only state conditions, such as ReentrantLock, RetrantReadWriteLock, and CountDownLatch, is customized by specific synchronizers according to specific scenarios

Check out some of the source code below:

  • Condition
public interface Condition { void await() throws InterruptedException; void signal(); void signalAll(); . }Copy the code
  • ReentrantLock
public class ReentrantLock implements Lock, java.io.Serializable { private final Sync sync; public Condition newCondition() { return sync.newCondition(); } abstract static class Sync extends AbstractQueuedSynchronizer { final ConditionObject newCondition() { return new ConditionObject(); }}}Copy the code
  • AbstractQueuedSynchronizer ConditionObject in inner class
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable { public class ConditionObject implements Condition, java.io.Serializable { private static final long serialVersionUID = 1173984872572414699L; /** First node of condition queue. */ private transient Node firstWaiter; /** Last node of condition queue. */ private transient Node lastWaiter; Public final void await() throws InterruptedException {//1.0 If the thread has been interrupted, do not wait  if (Thread.interrupted()) throw new InterruptedException(); //1.1. After wrapping the current thread, add it to a list maintained by the Condition. Conditionwaiter (); Int savedState = fullyRelease(node); int savedState = fullyRelease(node); int interruptMode = 0; /* set isOnSyncQueue to false; /* set isOnSyncQueue to false; Does not say that it is not yet competitive lock qualification, so continue to sleep. */ while (! isOnSyncQueue(node)) { LockSupport.park(this); if ((interruptMode = checkInterruptWhileWaiting(node)) ! = 0) break; } //1.4 isOnSyncQueue=true(isOnSyncQueue=true); If (acquireQueued(node, savedState) && interruptMode! = THROW_IE) interruptMode = REINTERRUPT; If (node.nextwaiter! = null) // clean up if cancelled unlinkCancelledWaiters(); //1.6 If (interruptMode! = 0) reportInterruptAfterWait(interruptMode); } //1.1 Conditionconditionwaiter () private Node addConditionWaiter() {Node t = lastWaiter; // If 't' is cancelled, clean out. // Ensure 't' is' lastWaiter 'If (t! = null && t.waitStatus ! = node.condition) {// clean up the previous Node. UnlinkCancelledWaiters (); t = lastWaiter; } // Create Node of type node.condition. Node Node = new Node(thread.currentThread (), node.condition); If (t == null) firstWaiter = node; if (t == null) firstWaiter = node; else t.nextWaiter = node; LastWaiter = node; return node; } final int fullyRelease(Node Node) {Boolean failed = true; try { int savedState = getState(); if (release(savedState)) { failed = false; return savedState; } else { throw new IllegalMonitorStateException(); } } finally { if (failed) node.waitStatus = Node.CANCELLED; Public final void signal() {//2.1 if (! isHeldExclusively()) throw new IllegalMonitorStateException(); //firstWaiter is the head Node of a linked list maintained by the condition. //2.2 Awaken the first node if (first! = null) doSignal(first); } private void doSignal(Node first) {doSignal(Node first) {doSignal(Node first) {doSignal(Node first) {doSignal(Node first) {doSignal(Node first) null;) If (firstWaiter = first.nextwaiter) == null) lastWaiter = null; Next = null first. NextWaiter = null; }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} transferForSignal(first) && (first = firstWaiter) ! = null); Final Boolean transferForSignal(Node Node) {/* * If cannot change waitStatus, */ // The node has been cancelled. */ // The node starts to compete for resources if (! compareAndSetWaitStatus(node, Node.CONDITION, 0)) return false; /* * Splice onto queue and try to set waitStatus of predecessor to * indicate that thread is (probably) waiting. If cancelled or * attempt to set waitStatus fails, Wake up to resync (in which * case the waitStatus can be transiently and harmlessly wrong). */ // Enq Will try to add a Node to the synchronization queue p = enq(node); int ws = p.waitStatus; if (ws > 0 || ! compareAndSetWaitStatus(p, ws, Node.SIGNAL)) LockSupport.unpark(node.thread); return true; }}}Copy the code
  • Conditions have a wait queue and a synchronization queue. There’s firstWaiter (pointing to first) and lastwaiter(pointing to last).
  • Each Condition has its own linked list queue (Node). It is a unidirectional linked list and stored by Node. If the value await() appends the node to the end, if woken it removes the header node and puts it on the synchronization queue.
  • If awakened, the first in the queue is awakened.

4. What’s the difference between wait,notify and Condition

  • Notify is a random wake-up thread. Condition is the specified thread.
  • Condition can have multiple queues in a thread (one queue per Condition), whereas wait and notify can only implement one queue.