“This is the 7th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

Hello, I’m looking at the mountains.

Java. Util. Concurrent. CyclicBarrier and JDK 1.5 provides a synchronous auxiliary class (why use also? See also CountDownLatch, which allows a group of threads to wait for each other until a common barrier point is reached. CyclicBarrier is useful in a program where a set of threads of a fixed size must wait for each other. Because this critical point can be reused after waiting for the thread to be released, it is said to be circular.

CyclicBarrier supports an optional Runnable that runs at the barrier point once (once per cycle Runnable) after the last thread in a set of threads completes and before all threads are released. This can be used to update the shared state (for example, checking weapons and ammo before the next zombie wave) before the next thread runs.

CountDownLatch and CyclicBarrier

CountDownLatch is not reusable. It is a one-time latch. Once the latch is unlocked, it cannot be reused. Like a fuse, it burns less when it’s lit, and then it can’t be used again. A CyclicBarrier is a circular method of locking that, once opened, can be counted and used again. Like an hourglass, it leaks this time and then the other way around.

Another big difference between the two is that CountDownLatch locks the main thread while waiting for the child threads, while CyclicBarrier does not lock the main thread but executes its optional Runnable thread by definition after all the child threads have finished.

So when you choose between these two helper classes, you can make a clear distinction.

CyclicBarrier instance

Let’s think about a situation where we need to import some data into the database, and if we don’t import a few items we want to time them so that we can look at them. Because the implementation is relatively simple, directly on the code:

import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;

public class CyclicBarrierTest {
    public static void main(String[] args) throws InterruptedException {
        final long start = System.currentTimeMillis();
        final CyclicBarrier barrier = new CyclicBarrier(3.new Runnable() {
            @Override
            public void run(a) {
                long end = System.currentTimeMillis();
                System.out.println("Import" + 3 + "Piece of data, total time so far:" + (end - start)
                        + "毫秒"); }});for (int i = 0; i < 9; i++) {
            final int threadID = i + 1;
            new Thread(new Runnable() {
                @Override
                public void run(a) {
                    try {
                        TimeUnit.SECONDS.sleep(new Random().nextInt(10));// Simulate business operations
                        System.out.println(threadID + "Complete import operation.");
                        barrier.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
        System.out.println("==== main thread end ===="); }}Copy the code

The execution result is as follows:

==== Main thread end ==== 4 Complete the import. 2 Complete the import operation. 1 Complete the import operation. Import three data pieces, total time: 4006 ms 5 Complete import operation. 6 Complete the import operation. 8 Complete the import. Import 3 pieces of data, total time: 4007 milliseconds 3 Complete import operation. 0 The import operation is complete. 7 Complete the import. Import three pieces of data, total time so far: 8006 millisecondsCopy the code

The program does not import 3 will be a time, statistics have been executed time. This is the total time if the number of CyclicBarrier constructors is equal to the number of for loops.

extension

Consider the example above. If the for loop is not an integer multiple of the number of CyclicBarrier listeners, such as 10, the result would be:

==== Main thread end ==== 2 Complete the import. 5 Complete the import operation. 4 Complete the import operation. Import 3 pieces of data, total time: 4005 milliseconds 8 complete import operation. 1 Complete the import operation. 3 Complete the import operation. Import 3 pieces of data, total time: 5005 ms 7 Complete import operation. 6 Complete the import operation. 0 The import operation is complete. Import 3 pieces of data, total time: 8005 ms 9 Complete import operation.Copy the code

9 Complete the import operation. After that, you’ll be waiting. Here you can see how many threads are short of reaching the barrier point by using barrier. GetNumberWaiting (). If this is the case, you need to use CountDownLatch. When all child threads have finished executing and the barrier. GetNumberWaiting () is not equal to zero, you can call the barrier. A BrokenBarrierException is raised at this point, but the entire process ends.

The modified code is as follows:

import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;

public class CyclicBarrierTest {
    public static void main(String[] args) throws InterruptedException {
        final long start = System.currentTimeMillis();
        final CountDownLatch count = new CountDownLatch(10);
        final CyclicBarrier barrier = new CyclicBarrier(3.new Runnable() {
            @Override
            public void run(a) {
                long end = System.currentTimeMillis();
                System.out.println("Import" + 3 + "Piece of data, total time so far:" + (end - start)
                        + "毫秒"); }});for (int i = 0; i < 10; i++) {
            final int threadID = i + 1;
            new Thread(new Runnable() {
                @Override
                public void run(a) {
                    try {
                        TimeUnit.SECONDS.sleep(new Random().nextInt(10));// Simulate business operations
                        System.out.println(threadID + "Complete import operation.");
                        count.countDown();
                        barrier.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        System.out.println("Raise the BrokenBarrierException exception.");
                    }
                }
            }).start();
        }
        count.await();
        
        if(barrier.getNumberWaiting() ! =0) {
            System.out.println("Not an integer multiple. Reset CyclicBarrier.");
            barrier.reset();
        }

        System.out.println("==== main thread end ===="); }}Copy the code

The execution result is as follows:

3 Complete the import operation. 9 Complete the import operation. 6 Complete the import operation. Import 3 pieces of data, total time: 3005 ms 8 Complete import operation. 5 Complete the import operation. 10 Complete the import. Import 3 pieces of data, total time: 7005 milliseconds 1 Complete import operation. 7 Complete the import. 4 Complete the import operation. 2 Complete the import operation. The total time taken to import three pieces of data: 9005 ms is not an integer multiple. Reset CyclicBarrier. ==== Main thread ends ==== BrokenBarrierException is raised.Copy the code

Reset with barrier. Reset (), because a CyclicBarrier is a loop that begins and ends, resetting can also be understood as completion.

Also, because CountDownLatch is used, the main thread is locked until the thread executes down through count.await().

Recommended reading

  • Java Concurrency Basics (1) : Synchronized
  • Java Concurrency Basics (2) : The main thread waits for the child thread to terminate
  • Java Concurrency basics (iii) : Talk more about CountDownLatch
  • Java Concurrency Basics (4) : CyclicBarrier
  • Java concurrency basics (5) : multithreaded sequential printing for interview practice

Hello, I’m looking at the mountains. Swim in the code, play to enjoy life. If this article is helpful to you, please like, bookmark, follow. Welcome to follow the public account “Mountain Hut”, discover a different world.