Implementation principle and application of CountDownLatch

Posted by Fatboy on Thu, 03 Mar 2022 14:58:55 +0100

1. Working principle of countdownlatch

CountDownLatch functions as a timer in multithreaded concurrent programming, and maintains a count variable, and its operations are atomic operations. This class mainly realizes its functions through countDown() and await(). First, it establishes a CountDownLatch object, and the incoming parameter is the initial value of count. If a thread calls the await () method, the thread enters the blocking state and enters the blocking queue. If a thread calls the countdown () method, it will make count-1; When the value of count is 0, the thread that calls the await () method in the queue will be awakened one by one, and then enter the subsequent operation. For example, the following example has two operations, one is a read operation and the other is a write operation. Now it is stipulated that the read operation can only be carried out after the write operation. Therefore, when the read operation is called at the beginning, you need to block it with the await () method. When the write operation ends, you need to make count equal to 0. Therefore, the initial value of count can be set as the number of records of write operation, so that write operation can be completed and then read operation can be carried out.

First, create the instance CountDownLatch countDown = new CountDownLatch(2)
After the thread to be synchronized is executed, count - 1; countDown.countDown()
For threads that need to wait for other threads to execute, call countdown Await() implements blocking synchronization


2. Application scenario


I gave a demo to demonstrate how to use it. Will this thing be used in the actual business scenario?

Because it is really used in a business scenario, otherwise it won't get this section alone

The details page of e-commerce is composed of many data assemblies. For example, it can be divided into the following modules

Shipping address and sales volume of the transaction
Basic information of goods (title, graphic details, etc.)
List of recommended products
Content of evaluation
....
The information of the above modules is obtained from different services and is not related to each other; Therefore, in order to improve the response, it can be made to obtain data concurrently, such as

Thread 1 obtains transaction related data
Thread 2 get basic information of goods
Thread 3 gets the recommended information
Thread 4 get evaluation information
....
However, when the data is finally assembled and returned to the front end, it can only be returned after all the above information is obtained. This scenario is very suitable for CountDownLatch

Call CountDownLatch#await(long, TimeUnit) in the thread that splits complete data, waiting for all module information to return.
The information acquisition of each module is executed by an independent thread; After executing, call CountDownLatch#countDown() to count -1.
 

3. Code demonstration

package cn.day13;
 
import java.util.concurrent.CountDownLatch;
 
public class Test {
 
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		final CountDownLatch latch = new CountDownLatch(2);
 
		new Thread() {
			public void run() {
				try {
					System.out.println("Child thread" + Thread.currentThread().getName()
							+ "Executing");
					Thread.sleep(3000);
					System.out.println("Child thread" + Thread.currentThread().getName()
							+ "completion of enforcement");
					latch.countDown();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			};
		}.start();
 
		new Thread() {
			public void run() {
				try {
					System.out.println("Child thread" + Thread.currentThread().getName()
							+ "Executing");
					Thread.sleep(3000);
					System.out.println("Child thread" + Thread.currentThread().getName()
							+ "completion of enforcement");
					latch.countDown();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			};
		}.start();
 
		try {
			System.out.println("Wait for 2 sub threads to complete execution...");
			latch.await();
			System.out.println("2 The child thread has finished executing");
			System.out.println("Continue with the main thread");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
 
}

Operation results:

 
 
  1. The child thread Thread-0 is executing

  2. Wait for 2 sub threads to complete execution

  3. The child thread Thread-1 is executing

  4. The execution of sub thread thread Thread-0 is completed

  5. The execution of sub thread thread Thread-1 is completed

  6. 2 sub threads have been executed

  7. Continue with the main thread

Code two

public class CountDownLatchDemo {
    private CountDownLatch countDownLatch;
 
    private int start = 10;
    private int mid = 100;
    private int end = 200;
 
    private volatile int tmpRes1, tmpRes2;
 
    private int add(int start, int end) {
        int sum = 0;
        for (int i = start; i <= end; i++) {
            sum += i;
        }
        return sum;
    }
 
 
    private int sum(int a, int b) {
        return a + b;
    }
 
    public void calculate() {
        countDownLatch = new CountDownLatch(2);
 
        Thread thread1 = new Thread(() -> {
            try {
                // Ensure that thread 3 executes with 1 and 2 first. It is blocked because the countDownLatch count is not 0
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName() + " : Start execution");
                tmpRes1 = add(start, mid);
                System.out.println(Thread.currentThread().getName() +
                        " : calculate ans: " + tmpRes1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                countDownLatch.countDown();
            }
        }, "Thread 1");
 
        Thread thread2 = new Thread(() -> {
            try {
                // Ensure that thread 3 executes with 1 and 2 first. It is blocked because the countDownLatch count is not 0
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName() + " : Start execution");
                tmpRes2 = add(mid + 1, end);
                System.out.println(Thread.currentThread().getName() +
                        " : calculate ans: " + tmpRes2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                countDownLatch.countDown();
            }
        }, "Thread 2");
 
 
        Thread thread3 = new Thread(()-> {
            try {
                System.out.println(Thread.currentThread().getName() + " : Start execution");
                countDownLatch.await();
                int ans = sum(tmpRes1, tmpRes2);
                System.out.println(Thread.currentThread().getName() +
                        " : calculate ans: " + ans);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "Thread 3");
 
        thread3.start();
        thread1.start();
        thread2.start();
    }
 
 
    public static void main(String[] args) throws InterruptedException {
        CountDownLatchDemo demo = new CountDownLatchDemo();
        demo.calculate();
 
        Thread.sleep(1000);
    }
}

 

Operation results

 
 
 
  1. Thread 3: start execution

  2. Thread 1: start execution

  3. Thread 2: start execution

  4. Thread 1: calculate ans: 5005

  5. Thread 2: calculate ans: 15050

  6. Thread 3: calculate ans: 20055

Article reprint:

Implementation principle and application of CountDownLatch

Topics: Java Front-end