Java - CyclicBarrier

[Updated: Jul 30, 2017, Created: Jul 30, 2017]

In Java, a CyclicBarrier allows a set of threads (parties) to all wait for each other to reach a common barrier point.

A CyclicBarrier is initialized with a given count (the parties). Let's say this count is N.

The method CyclicBarrier#await() decreases the count N by 1. The calling threads waits until N becomes zero i.e. all threads (parties) have invoked await() on this barrier.

There is another overloaded method await(long timeout, TimeUnit unit), which can specify a max waiting time.

CyclicBarrier can be useful for multiple purposes, for example a number of threads can be paused for other threads to reach to a certain point before progressing. This functionality is similar to CountDownLatch, but main difference with CyclicBarrier is; it does not have method countDown(). The method CyclicBarrier#await() takes care of both blocking the threads at the barrier point and decreasing the underlying count. Also unlike CountDownLatch, CyclicBarrier can reuse the underlying count over and over again. CountDownLatch's underlying count when reaches to zero, cannot be reset to the initial count.

CyclicBarrier is synchronized internally, so it can be used by multiple threads safely. Also actions in a thread before calling await() establish happen-before relation with all actions following a successful return from await() in this and all other threads.

Let's understand CyclicBarrier with an example.

Example

public class CyclicBarrierExample {
  private static final int THREAD_COUNT = 4;
  public static void main(String[] args) {
      CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT);
      JFrame frame = createFrame();
      frame.setLayout(new FlowLayout(FlowLayout.LEFT));

      for (int i = 1; i <= THREAD_COUNT; i++) {
          ProgressThread progressThread = new ProgressThread(barrier, i * 10);
          frame.add(progressThread.getProgressComponent());
          progressThread.start();
      }
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
  }

  private static JFrame createFrame() {
      try {
          UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
      } catch (Exception e) {
          e.printStackTrace();
      }
      JFrame frame = new JFrame("Java CyclicBarrier Example");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setSize(new Dimension(ProgressThread.PROGRESS_WIDTH, 170));
      return frame;
  }

}
public class ProgressThread extends Thread {
  public static final int PROGRESS_WIDTH = 350;
  private static final int CATCH_UP_MULTIPLE = 25;
  private final JProgressBar progressBar;
  private final CyclicBarrier barrier;
  private final int slowness;

  public ProgressThread(CyclicBarrier barrier, int slowness) {
      this.barrier = barrier;
      this.slowness = slowness;
      progressBar = new JProgressBar();
      progressBar.setPreferredSize(
              new Dimension(PROGRESS_WIDTH - 30, 25));
      progressBar.setStringPainted(true);
  }

  JComponent getProgressComponent() {
      return progressBar;
  }

  @Override
  public void run() {

      int c = 0;
      boolean reversed = false;
      while (true) {
          progressBar.setValue(reversed ? --c : ++c);
          if (c == 100) {
              reversed = true;
          } else if (c == 0) {
              reversed = false;
          }

          try {
              Thread.sleep(slowness);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }

          if (c % CATCH_UP_MULTIPLE == 0) {//if c is multiple of CATCH_UP_MULTIPLE
              try {
                 /**
                              * This is the barrier point.
                              * On calling await() method, the current thread (party)
                              * will wait until all threads (parties) have called this
                              * method. At this method call
                              * barrier.getNumberWaiting() will increase by one.*/
                  barrier.await();
                  //at this point no threads will be waiting and
                  // barrier.getNumberWaiting() will be zero
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      }
  }
}

Output

The CyclicBarrier logic from above example can be used with some useful multiple tasks which want to submit their individual work at the barrier point and then start with some initial parameters again.

Example Project

Dependencies and Technologies Used :

  • JDK 1.8
  • Maven 3.3.9

CyclicBarrier Example Select All Download
  • cyclic-barrier-example
    • src
      • main
        • java
          • com
            • logicbig
              • example

See Also