How to use CountDownLatch in creating threads so that they add messages into the list the order I call?

86 Views Asked by At

I am trying to use CountDownLatch, so that the fourth and fifth threads starts running only after the start of first three threads and these threads add messages into the result list while they are running.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;

public class ThreadExample {
    private static List<String> resultList = new ArrayList<>();
    
    public static void main(String[] args) {
        int numberOfThreads = 3;
        CountDownLatch latch = new CountDownLatch(numberOfThreads);

        // Create and start first 3 threads using createThread method
        createThread("threadName1", "message1", latch);
        createThread("threadName2", "message2", latch);
        createThread("threadName3", "message3", latch);

        try {
            // Wait for the first 3 threads to finish
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        createUpdateThread("updateThread", "finishThread");
        if (resultList.size() != 3) {

            throw new IllegalStateException("The size of the list is not equal to 3.");
        }
        createThread("threadName4", "message4", latch);

        // Wait for all threads to finish
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Result List: " + resultList);
    }

    private static void createThread(String threadName, String message, CountDownLatch latch) {
        Thread thread = new Thread(() -> {
            // Insert threadName to the resultList
            resultList.add(threadName);
            latch.countDown(); // Decrease the latch count
            // some functional code
        });

        // Start the thread
        thread.start();
    }

    private static void createUpdateThread(String updateThread, String finishThread) {
        Thread thread = new Thread(() -> {
            // Insert updateThread to the resultList
            resultList.add(updateThread);
            //some functional code
            // Insert finishThread to the resultList
            resultList.add(finishThread);
        });

        // Start the thread
        thread.start();
    }
}

After careful consideration, I have decided that the specific order of thread starts is not a critical requirement for my current implementation. I made necessary changes to my code to accomplish my requirement.

1

There are 1 best solutions below

0
On BEST ANSWER

If you want to control the threads from the central place (the main method in your case) then you don't need any CountDownLatch. Simple Thread.join() would be enough.

So here's your refactored code:

class ThreadExample {
    private static Queue<String> resultList = new LinkedBlockingQueue<>();

    public static void main(String[] args) {
        List<Thread> firstThreeThreads = Arrays.asList(
                createThread("threadName1", latch),
                createThread("threadName2", latch),
                createThread("threadName3", latch)
        );

        List<Thread> lastTwoThreads = Arrays.asList(
                createThread("threadName4", latch),
                createUpdateThread("updateThread", "finishThread")
        );

        firstThreeThreads.forEach(Thread::start);
        firstThreeThreads.forEach(ThreadExample::joinThread);

        if (resultList.size() != 3)
            throw new IllegalStateException("The size of the list is not equal to 3.");

        lastTwoThreads.forEach(Thread::start);
        lastTwoThreads.forEach(ThreadExample::joinThread);

        System.out.println("Result List: " + resultList);
    }

    private static void joinThread(Thread thread) throws RuntimeException {
        try {
            thread.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    private static Thread createThread(String threadName, CountDownLatch latch) {
        return new Thread(() -> {
            // Insert threadName to the resultList
            resultList.add(threadName);
            // some functional code
        });
    }

    private static Thread createUpdateThread(String updateThread, String finishThread) {
        return new Thread(() -> {
            // Insert updateThread to the resultList
            resultList.add(updateThread);
            //some functional code
            // Insert finishThread to the resultList
            resultList.add(finishThread);
        });
    }
}

Another thing I needed to change is the collection where you put your results. You shouldn't use simple List<> for that. The LinkedBlockingQueue<> would be more suitable here. Remember if you use a shared resource across threads then this resource must be thread safe. Otherwise, there is no guarantee that changes would be visible in your main thread.

The reason you didn't see results in your resultList was because you didn't wait for the last two threads to finish. The System.out.println("Result List: " + resultList); was run before the fourth and fifth threads finished. So the whole program finished, while the last two thread were still running. In my code it was fixed by calling joinThread() for the second time.