CountDownLatch

CountDownLatch is a very useful multithreaded control tool class. Latch stands for door latch, and this tool is designed to address situations in which certain operations can only be performed after a set of operations have all been performed. For example, an amusement park roller coaster can seat 10 people at a time. In order to save costs, it is usually waited for 10 people to ride. CountDownLatch is a count-down count, so the use of CountDownLatch is usually to set a value greater than 0, which represents the total number of tasks to wait for. After each task is completed, the total number of tasks is subtracted by one until the value is 0, which means that all the waiting tasks have been executed and the latch is opened. Subsequent tasks can continue.

The constructor of CountDownLatch takes an integer that represents the number of current counters.

public CountDownLatch(int count)
Copy the code

Core method

// Count by 1
public void countDown(a)
/ / wait for
public void await(a) throws InterruptedException
// Wait with timeout mechanism
public boolean await(long timeout, TimeUnit unit) throws InterruptedException
Copy the code

CountDown () the underlying implementation of the counting logic

protected boolean tryReleaseShared(int releases) {
    // Decrement count; signal when transition to zero
    for (;;) {
        int c = getState();
        if (c == 0)
            return false;
        int nextc = c-1;
        if (compareAndSetState(c, nextc))
            return nextc == 0; }}Copy the code

The implementation of this method is simply to get the current state value and return false if it is already zero. This method returns true only if the count value is not originally zero, and then returns false otherwise. This method returns false only if the count value is not originally zero, and then returns false again. It’s still going to return false. That is, there is only one case where calling this method will return true, and that is when the state value goes from greater than zero to zero, at which point all the work in front of the latch is done.

After the tryReleaseShared() method is executed, if the result is true, the doReleaseShared() method continues to wake up the waiting thread.

A simple example

public class CountDownLatchTest {

    public static void main(String[] args) throws InterruptedException {

        CountDownLatch latch = new CountDownLatch(10);
        ExecutorService executorService = Executors.newFixedThreadPool(10);

        for (int i = 0; i < 10; i++) {
            executorService.submit(
                    () -> {
                        action();
                        latch.countDown(); // -1
                    });
        }
        // Wait for completion
        // The latch counter >0 will be blocked
        latch.await();
        System.out.println("Passengers full, roller coaster starts.");
        executorService.shutdown();
    }

    private static void action(a) {
        System.out.printf("Tourists [%s] are riding a roller coaster... \n", Thread.currentThread().getName()); }}Copy the code

There are 10 seats for the ride, and the ride starts only when it is full, that is, the thread waits on the CountDownLatch until the counter is zero, and the main ride continues.

CyclicBarrier

CyclicBarrier is another multi-threaded concurrency control utility. Like CountDownLatch, it can count waits between threads, but it is more powerful than CountDownLatch.

CyclicBarrier can be understood as a cycle barrier. It is used to prevent the thread from continuing execution by requiring it to wait at the fence. The previous word Cyclic means cycle, meaning that the counter can be used repeatedly. For example, if we set the counter to 10, the counter will return to zero when the first 10 threads are collected, and then the next 10 threads are collected.

The constructor

public CyclicBarrier(int parties)
public CyclicBarrier(int parties, Runnable barrierAction)
Copy the code
  • Parties is the number of participating threads
  • The second constructor takes a Runnable argument, which means the callback function to call when the counter is reduced to zero.

Core method

// CyclicBarrier.await() = CountDownLatch.countDown() + await()
public int await(a) throws InterruptedException, BrokenBarrierException
Copy the code

Await () method might sell Java. Util. Concurrent. BrokenBarrierException abnormalities, once throw this exception is representative of current CyclicBarrier damaged, all threads may system has no way to wait here. The reason for the corruption may be that one of the threads is interrupted or timed out while awaiting ().

A simple example

public class CyclicBarrierDemo {

    static class TaskThread extends Thread {

        CyclicBarrier barrier;

        public TaskThread(CyclicBarrier barrier) {
            this.barrier = barrier;
        }

        @Override
        public void run(a) {
            try {
                Thread.sleep(1000);
                System.out.println(getName() + "Reach fence A");
                barrier.await();
                System.out.println(getName() + "Break through the fence A");

                Thread.sleep(2000);
                System.out.println(getName() + "Reach fence B");
                barrier.await();
                System.out.println(getName() + "Break through the fence B");
            } catch(Exception e) { e.printStackTrace(); zzzzzz } } }public static void main(String[] args) {
        int threadNum = 5;
        CyclicBarrier barrier = new CyclicBarrier(threadNum, () -> System.out.println("Finish the last mission."));

        for(int i = 0; i < threadNum; i++) {
            newTaskThread(barrier).start(); }}}Copy the code

CountDownLatch is compared with CyclicBarrier

CountDownLatch CyclicBarrier
Subtraction counting Add count mode
All waiting threads are released when the value is 0 All waiting threads are released when the count reaches a specified value
The count cannot be reset when it is 0 When the count reaches the specified value, the count is set to 0 and restarted
Calling countDown() reduces the count by one, and calling await() blocks only and has no effect on the count The awit() method is called to increment the count by one, and if the increment does not equal the value of the constructor, the thread blocks
Unrepeatable reusability

conclusion

  1. CountDownLatchMainly used to solve a thread waiting for multiple threads scenario;
  2. CyclicBarrierIs a set of threads waiting for each other;
  3. CountDownLatchThe counter of is not recyclable, that is, once the counter is reduced to 0 and another thread calls await(), the thread will pass directly through;
  4. CyclicBarrierThe counter is recyclable and has an automatic reset function. Once the counter drops to zero, it will automatically reset to the initial value you set. You can also set a callback function.