Waiting for another thread with CountDownLatch: 2 Real-life examples

March 21, 2018

Category: The package java.util.concurrent

CountDownLatch is an easy way to wait till another thread has finished a task. The CountDownLatch is initialized by the number of threads we need to wait for. After a thread has finished its task it calls countDown, counting down the countdown. A thread can wait till the countdown reaches zero by calling await. We will see how to use it by looking at two real-life examples.

How to use CountDownLatch: Waiting for initialization

The apache ignite CacheDataStructuresManager needs to wait till it is initialized. One thread initializes the CacheDataStructuresManager so we need a CountDownLatch with count one:

private final CountDownLatch initLatch = new CountDownLatch(1);

The initialization is done in the onKernalStart0() method:

    @Override protected void onKernalStart0() 
                        throws IgniteCheckedException {
        try {
            queueHdrView = cctx.cache();
            initFlag = true;
        }
        finally {
            initLatch.countDown();
        }
    }

The countDown method is called in the finally block. So we guarantee that the countdown eventually reaches zero and we do not wait forever. To signal that the initialization was successful we use the boolean flag initFlag.

The method waitInitialization is used to check if the initialization was successful:

    private void waitInitialization() 
             throws IgniteCheckedException {
        if (initLatch.getCount() > 0)
            U.await(initLatch);
        if (!initFlag)
            throw new IgniteCheckedException(
               "DataStructures manager was not properly initialized.");
    }

We check the count of the CountDownLatch waiting if necessary in the await method from IgniteUtils. After that, we check the initFlag if the initialization was successful.

The method await from IgniteUtils handles the InterruptedException from the CountDownLatch await method:

    public static void await(CountDownLatch latch) 
                  throws IgniteInterruptedCheckedException {
        try {
            if (latch.getCount() > 0)
                latch.await();
        }
        catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IgniteInterruptedCheckedException(e);
        }
    }

In the example the interrupt flag is restored by calling Thread.currentThread().interrupt() and a new checked Exception is thrown.

Handling of InterruptedException

The await method of the CountDownLatch throws an InterruptedException when the method Thread.interrupt was called. the CountDownLatch clears the interrupt flag when it throws the InterruptedException. Therefore the book Java Concurrency in Practice - Brian Goetz, et al. recommends to either propagate the InterruptedException or to restore the interrupt flag.

The guava library provides the utility method awaitUninterruptibly in the class Uninterruptibles which implements the second recommendation. It restores the interrupt flag. Using this method you make sure that another blocking method will again throw an InterruptedException.

How to use await with a timeout: Testing multithreaded software.

The next example shows how to call the second method to wait for other threads, await with a timeout: This method is typically used in tests, like in this example in the PostServletTest from jetty:

    @Test
    public void testBadPost() throws Exception
    {
        StringBuilder req = new StringBuilder(16*1024);
        // creation of the request String omitted
        String resp = connector.getResponse(req.toString());
        assertThat(resp,startsWith("HTTP/1.1 200 OK")); 
        assertTrue(complete.await(5,TimeUnit.SECONDS));
        assertThat(ex0.get(),not(nullValue()));
        assertThat(ex1.get(),not(nullValue()));
    }

The await method gets called with the amount we want to wait together with the unit for the amount, line 8. In our example, we want to wait no more than 5 seconds. The test fails when the await method returns false because of the timeout.

Other classes to wait for threads

Java provides three classes to wait for other threads: CountDownLatch, CyclicBarrier, and Phaser. When you need to wait for tasks done in other threads use CountDownLatch. Use CyclicBarrier when you do the work and need to wait in the same threads. To use CyclicBarrier or CountDownLatch you need to know the number of threads when you call the constructor. If you need to add threads after construction time, use the class Phaser.

Summary and next steps

When you want to wait for another thread with CountDownLatch follow these steps:

  1. Initialize the CountDownLatch with the number of threads you are waiting for.
  2. Call the countDown method in the finally block when a thread has finished its task.
  3. Use a flag or counter to signal that the tasks were successful.
  4. Wait for the threads with the method await. Propagate the InterruptedException thrown by await or restore the interrupted flag when you catch the InterruptedException.

The CountDownLatch can only be used once. We will look at the CyclicBarrier next, which can be used multiple times. I would be glad to hear from you about how you use CountDownLatch in your application.

testing multi-threaded applications on the JVM made easy

LEARN MORE

© 2020 vmlens Legal Notice Privacy Policy