Condition (a more efficient way for threads to communicate). For more information, please click on the portal:

The path to learning asynchronous programming (7) -Lock (a better way to deal with synchronization problems)

In this article, we’ll take a closer look at the Condition method in Lock.

The Condition breaks the Object monitor methods (WAIT, notify, and notifyAll) into distinct objects in order to provide multiple wait sets (wait-sets) for each Object by combining these objects with any Lock implementation. Where, Lock replaces the use of synchronized method and statement, Condition replaces the use of Object monitor method, the code is as follows:

public class ThreadTest2 {
	public static void main(String[] args) {
		final Business business = new Business();
		new Thread(new Runnable() {
			@Override
			public void run(a) {
				threadExecute(business, "sub");
			}
		}).start();
		threadExecute(business, "main");
	}	
	public static void threadExecute(Business business, String threadType) {
		for(int i = 0; i < 100; i++) {
			try {
				if("main".equals(threadType)) {
					business.main(i);
				} else{ business.sub(i); }}catch(InterruptedException e) { e.printStackTrace(); }}}}class Business {
	private boolean bool = true;
	private Lock lock = new ReentrantLock();
	private Condition condition = lock.newCondition(); 
	public void main(int loop) throws InterruptedException {
		lock.lock();
		try {
			while(bool) {				
				condition.await();//this.wait();
			}
			for(int i = 0; i < 100; i++) {
				System.out.println("main thread seq of " + i + ", loop of " + loop);
			}
			bool = true;
			condition.signal();//this.notify();
		} finally{ lock.unlock(); }}public void sub(int loop) throws InterruptedException {
		lock.lock();
		try {
			while(! bool) { condition.await();//this.wait();
			}
			for(int i = 0; i < 10; i++) {
				System.out.println("sub thread seq of " + i + ", loop of " + loop);
			}
			bool = false;
			condition.signal();//this.notify();
		} finally{ lock.unlock(); }}}Copy the code

In Condition, we can replace wait() with await(), notify() with signal(), and notifyAll() with signalAll(). Condition is bound to Lock, and to create a Lock Condition must use the newCondition() method.

In this way, Condition is no different from traditional thread communication. The power of Condition is that it can create different conditions for multiple threads.

class BoundedBuffer {
   final Lock lock = new ReentrantLock();/ / lock object
   final Condition notFull  = lock.newCondition();// Write thread conditions
   final Condition notEmpty = lock.newCondition();// Read thread conditions
 
   final Object[] items = new Object[100];// Cache the queue
   int putptr/* Write index */, takeptr/* Read index */, count/* Number of data in the queue */;
 
   public void put(Object x) throws InterruptedException {
     lock.lock();
     try {
       while (count == items.length)// If the queue is full
         notFull.await();// Block the writer thread
       items[putptr] = x;/ / assignment
       if (++putptr == items.length) putptr = 0;// If the index is written to the last position in the queue, set it to 0
       ++count;/ / the number of + +
       notEmpty.signal();// Wake up the reader thread
     } finally{ lock.unlock(); }}public Object take(a) throws InterruptedException {
     lock.lock();
     try {
       while (count == 0)// If queue is empty
         notEmpty.await();// Block the read thread
       Object x = items[takeptr];/ / value
       if (++takeptr == items.length) takeptr = 0;// If the read index reaches the last position in the queue, set it to 0
       --count;/ / the number -
       notFull.signal();// Wake up the writer thread
       return x;
     } finally{ lock.unlock(); }}}Copy the code

The cache provides two methods, put and take. Put is for storing data, and take is for fetching data. There is an internal cache queue. Have multiple threads to save data and fetch the data from the inside, the buffer queue (first in first out) after a junior can cache the maximum value is 100, among multiple threads are mutually exclusive, when stored in the cache queue value reaches 100, will write thread blocks, and awaken the reader thread, when stored in the cache queue value is 0, the reader thread blocking, and wake up to write a thread, This is also an internal implementation of ArrayBlockingQueue. The following code execution process is analyzed:

1. A writer thread executes, calling the PUT method;

Count = 100; count = 100;

3. Run the command to save the value.

4. Check whether the current written index position ++ is equal to 100. If the value is equal, the index value is changed to 0 and count+1 is changed.

5. Wake up only one reader thread blocking queue.

6. A reader thread executes, calling the take method;

Wake up only one writer thread blocking queue.

This is the power of multiple conditions, if the cache queue is full, then the writer thread must be blocking and the reader thread must be waking up, and on the contrary, the reader thread must be blocking and the writer thread must be waking up, so what’s the effect of just one Condition, if the cache queue is full, The Lock doesn’t know if it woke up the reader thread or the writer thread, so if it woke up the reader thread, everybody’s happy, but if it woke up the writer thread, it just woke up, blocked, and woke up again, so it wasted a lot of time.