Search code examples
javaconcurrencyjava.util.concurrent

CountDownLatch - understanding await and countDown


According to Javadoc: A CountDownLatch is initialized with a given count. The await methods block until the current count reaches zero.

That means in the below code, since I initialized the CountDownLatch to 1. All threads should get unblocked from its await method as soon as the latch calls countdown.

But, the main thread is waiting for all the threads to complete. And also, I didn't join the main thread to end of the other threads. Why is the main thread waiting?

    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.atomic.AtomicLong;

public class Sample implements Runnable {

    private CountDownLatch latch;

    public Sample(CountDownLatch latch)
    {
        this.latch = latch;
    }
    private static AtomicLong number = new AtomicLong(0);

    public long next() {
         return number.getAndIncrement();
    }

    public static void main(String[] args) {

        CountDownLatch latch = new CountDownLatch(1);
        for (int threadNo = 0; threadNo < 4000; threadNo++) {
          Runnable t = new Sample(latch);
          new Thread(t).start();
        }
        try {
            latch.countDown();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        try {
            latch.await();
            Thread.sleep(100);
            System.out.println("Count:"+next());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

Solution

  • Try running the following modified version of your code:

    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.atomic.AtomicLong;
    
    public class Test implements Runnable {
    
        private CountDownLatch latch;
    
        public Test(CountDownLatch latch)
        {
            this.latch = latch;
        }
        private static AtomicLong number = new AtomicLong(0);
    
        public long next() {
             return number.getAndIncrement();
        }
    
        public static void main(String[] args) {
    
            CountDownLatch latch = new CountDownLatch(1);
            for (int threadNo = 0; threadNo < 1000; threadNo++) {
              Runnable t = new Test(latch);
              new Thread(t).start();
            }
            try {
                latch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            System.out.println( "done" );
        }
    
        @Override
        public void run() {
            try {
                Thread.sleep(1000 + (int) ( Math.random() * 3000 ));
                System.out.println(next());
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                latch.countDown();
            }
        }
    
    }
    

    You should see something like:

    0
    done
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    This indicates that the main thread did, in fact, unblock from the latch.await() call after the first thread called latch.countDown()