Learn java thread communication with me 3:CyclicBarrier

1. Introduction

This post would demo how to do the thread communication by using CountDownLatch. If you want to know the wait-notify communication, you can refer to the previous article, if you want to learn how to communicate through the volatile keyword, you can refer to this article,if you want to learn how to use CountDownLatch, you can view this post

1. Environments

  • Java 1.8

2.1 The CyclicBarrier introduction

As the javadoc says:

It’s a synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point. CyclicBarriers are useful in programs involving a fixed sized party of threads that must occasionally wait for each other. The barrier is called cyclic because it can be re-used after the waiting threads are released.

A CyclicBarrier supports an optional Runnable command that is run once per barrier point, after the last thread in the party arrives, but before any threads are released. This barrier action is useful for updating shared-state before any of the parties continue.

The CyclicBarrier is very similar to the CountDownLatch, the difference is the CyclicBarrier can be reused and is controlled in every thread.

This picuture shows how the CyclicBarrier works:

20180520_thread_CyclicBarrier

As the picture shows:

  • There are three threads in the barrier, they are waiting for each other
  • Worker0 runs fast, and it’s waiting for the max time
  • Worker1 runs slower than worker0, and is also waiting for some time
  • Worker2 runs slowest, and after it reaches the barrier, all threads unlocked
  • The barrier executes the “allTaskDone” thread when all threads unlocked

2.2 The classic CyclicBarrier example code

    public static void main(String[] args) throws InterruptedException {
        int N = 3;
        CyclicBarrier barrier = new CyclicBarrier(N,()-> log.debug("all workers done"));
        log.debug("starting the workers...");
        for(int i=1;i<=N;i++) {
            Worker worker = (new Worker("worker"+i,i*2000,barrier));
            worker.start();
        }
    }
    private static class Worker extends Thread {
        private final long sleepTime;
        private final CyclicBarrier barrier;
        public Worker(String name, long sleepTime, CyclicBarrier barrier) {
            super(name);
            this.sleepTime = sleepTime;
            this.barrier = barrier;
        }
        public void run() {
            try {
                log.debug(getName()+" started...");
                Thread.sleep(sleepTime);
                log.debug(getName()+" waiting...");
                int arriveIndex = barrier.await();
                log.debug(getName()+" arrived barrier at "+arriveIndex);
            }catch (Exception ex) {
                ex.printStackTrace();
            }finally {
            }
        }
    }
  • Each worker sleep for some time and call barrier.await to wait for the others
  • The worker3 is the slowest thread
  • The CyclicBarrier has 3 threads and one action, the action just print ‘all workers done’

Run the code and we get this:

20:24:33.857 [main]    DEBUG threadComm4_1 - starting the workers...
20:24:33.900 [worker1] DEBUG threadComm4_1 - worker1 started...
20:24:33.900 [worker2] DEBUG threadComm4_1 - worker2 started...
20:24:33.900 [worker3] DEBUG threadComm4_1 - worker3 started...
20:24:35.903 [worker1] DEBUG threadComm4_1 - worker1 waiting...
20:24:37.905 [worker2] DEBUG threadComm4_1 - worker2 waiting...
20:24:39.905 [worker3] DEBUG threadComm4_1 - worker3 waiting...
20:24:39.906 [worker3] DEBUG threadComm4_1 - all workers done
20:24:39.906 [worker3] DEBUG threadComm4_1 - worker3 arrived barrier at 0
20:24:39.906 [worker1] DEBUG threadComm4_1 - worker1 arrived barrier at 2
20:24:39.906 [worker2] DEBUG threadComm4_1 - worker2 arrived barrier at 1

Process finished with exit code 0

As you can see

  • workers started and then waiting
  • after worker3 done, then ‘all workers done’ action executed
  • we print the arrive index of every worker, the zero means the last

3. Summary

The CyclicBarrier is more flexible than CountDownLatch.

You can find the whole code examples on github project, the class source code is located at this, they are named like ThreadComm4_*.java

You can find detail documents about the java stream here: