Managing Concurrent Processes

The Concurrency API includes classes that can be used to coordinate tasks among a group of related threads. These classes are designated for use in some specific scenarios. One of the most used classes for coordinating concurrent tasks are CyclicBarrier and ForkJoinPool.

Assume that several janitors have to clean kids playground. The best way to do it is first letting kids and their older guards (parents/grandparents/custodians etc) leave the playground, then cleaning it, and after that welcoming visitors back. Of course, it is better to have all the work completed by all janitors concurrently, pausing between the end of one set of tasks and the start of the next. That is where CyclicBarrier can be very useful. A code sample without the CyclicBarrier will look like this :

public class NoCyclicBarrierExample {
    private void removeVisitors() {
        System.out.println("Removing visitors");
    }

    private void cleanPlayground() {
        System.out.println("Cleaning the playground");
    }

    private void addVisitors() {
        System.out.println("Adding visitors");
    }

    private void performTask() {
        removeVisitors();
        cleanPlayground();
        addVisitors();
    }

    public static void main(String[] args) {
        ExecutorService service = null;
        try {
            service = Executors.newFixedThreadPool(3);
            NoCyclicBarrierExample noCyclicBarrierExample = new NoCyclicBarrierExample();
            for (int i = 0; i < 3; i++) {
                service.submit(() -> noCyclicBarrierExample.performTask());
            }
        } finally {
            if (service != null) {
                service.shutdown();
            }
        }
    }
}

One of the possible outputs will be

Removing visitors
Removing visitors
Cleaning the playground
Removing visitors
Cleaning the playground
Adding visitors
Adding visitors
Cleaning the playground
Adding visitors

Although within each single thread the results are ordered, among multiple janitors the output is entirely random. It can be improved by using the CyclicBarrier class.The CyclicBarrier takes in its constructors a limit value, indicating the number of threads to wait for. As each thread finishes, it calls the await() method on the cyclic barrier. Once the specified number of threads have each called await(), the barrier is released and all threads can continue. The following is a reimplementation of the same functionality that uses CyclicBarrier objects to coordinate access :

Next

Leave a Reply

Your email address will not be published. Required fields are marked *