java multithreading: 17. CountDownLatch of J.U.C

introduce

CountDownLatch is a counting latch, which is somewhat similar to CyclicBarrier.

It is described in the API as follows:

Initializes CountDownLatch with the given count. Because the countDown() method is called, the thread calling the await method will be blocked until the current count reaches zero. When the count reaches zero, all waiting threads will be released and all subsequent calls to await will return immediately.

This happens only once - the count cannot be reset. If you need to reset the count, consider using CyclicBarrier.

  • CountDownLatch: one or more threads wait for other threads to complete something before they can execute. The waiting thread calls the await method, and other threads call the countDown method to decrement after completing something
  • CyclicBarrier: multiple threads wait for each other until they reach the same synchronization point, and then continue to execute together. You can specify a thread through the construction method. When the waiting thread meets the conditions, it will take priority to execute this thread,

For CountDownLatch, the focus is "one thread or multiple threads waiting". After the specified number of threads completes "something", you can terminate or wait. For CyclicBarrier, the key point is that if any thread in multiple threads fails to complete, all threads must wait.

CountDownLatch is implemented through a counter. The initial value of the counter is the number of threads. Every time a thread completes its task, the value of the counter will be reduced by 1. When the counter value reaches 0, it indicates that all threads have completed the task, and then the waiting threads can resume execution. As shown below

Implementation analysis

The CountDownLatch structure is as follows

From the above structure diagram, we can see that CountDownLatch internally relies on Sync implementation, and Sync inherits AQS.

Construction method

CountDownLatch provides only one construction method:

  • CountDownLatch(int count): construct a CountDownLatch initialized with a given count
public CountDownLatch(int count) {
    if (count < 0) throw new IllegalArgumentException("count < 0");
    this.sync = new Sync(count);
}

Sync is an internal class of CountDownLatch. Through this internal class, sync can know that CountDownLatch is implemented with shared lock

common method

  • await() (note not the wait method): causes the current thread to wait until the latch counts down to zero, unless the thread is interrupted. Internally, the getState method of AQS is used to obtain the counter. If the counter value is not equal to 0, it will try to obtain the synchronization state all the time in the form of spin.
  • countDown(): decrements the count of the latch. If the count reaches zero, all waiting threads will be released. Internally call the releaseShared(int arg) method of AQS to release the shared lock synchronization state.

case

Modify the application scenario of CyclicBarrier and add relay athletes.

Starting athletes should wait until other starting athletes are ready to start (CyclicBarrier).

Relay athletes don't need to care about others. They just need the starting point athletes related to themselves to start running at the relay point.

    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(10,()->{
            System.out.println("-----------------------Five athletes and five relay athletes are all in place and start running--------------");
        });

        List<Thread> threads = new ArrayList<>();

        for (int i = 0; i < 5; i++) {
            CountDownLatch countDownLatch = new CountDownLatch(1);
            threads.add(new Thread(()->{
                try {
                    System.out.println(Thread.currentThread().getName() + "--->Already in place");
//                    Waiting for other athletes
                    cyclicBarrier.await();
                    System.out.println(Thread.currentThread().getName() + "--->The handover point has been reached");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }finally {
//                    Inform relay athletes
                    countDownLatch.countDown();
                }
            },"Athletes:"+i));
            threads.add(new Thread(()->{
                try {
                    System.out.println(Thread.currentThread().getName() + "--->Already in place");
//                    Waiting for other relay athletes
                    cyclicBarrier.await();
//                    Waiting for the starter to give me a stick
                    countDownLatch.await();
                    System.out.println("congratulations " + Thread.currentThread().getName() + "---> Reach the handover point");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            },"Relay athletes:"+i));
        }
        for (Thread thread : threads) {
            thread.start();
        }
    }

Tags: JUC

Posted by janice on Wed, 11 May 2022 07:35:09 +0300