Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.


CountDownLatch and CyclicBarrier, as synchronization control tool classes under JUC toolkit, are frequently used in our work. Their functions are similar, but there are also certain differences. In this paper, we combine the specific code examples to analyze the use and differences between the two.

CountDownLatch

The CountDownLatch can be viewed as a counter, and the counter operation is atomic. Only one thread can operate the counter, i.e., only one thread can reduce the value of the counter. Let’s take a look at some important methods in common use, starting with constructors:

CountDownLatch countDownLatch=new CountDownLatch(count);
Copy the code

The count passed in the constructor is of type int, and the initial value of this counter is the number of threads to wait. This value can only be set once, and CountDownLatch does not provide any method to change or reset the value.

CountDown method:

countDownLatch.countDown();
Copy the code

This method is called whenever a thread has completed its task, and the value of the counter is reduced by one. When the counter value is 0, all threads have completed their work, and the threads waiting on the lock can resume their work.

Await method:

countDownLatch.await();
Copy the code

The main thread usually calls this method after starting another thread, so that the main thread’s operations are blocked on this method until the other threads finish their work. Typically, the first interaction with CountDownLatch is here, where the main waits for other threads.

Let’s take an example to see the specific use: Suppose we query tickets through a third-party agency, and the third party will count the available tickets of each airline and return the results after all the queries are completed. The main thread:

public class CountDownDemo {
    private static List<String> company= Arrays.asList("ShanHang"."东航"."Green traffic");
    private static List<String> flightList=new ArrayList<>();

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch=new CountDownLatch(company.size());
        for (int i = 0; i < company.size(); i++) {
            String name=company.get(i);
            QueryThread queryThread=new QueryThread(countDownLatch,flightList,name);
            new Thread(queryThread).start();
        }
        countDownLatch.await();
        System.out.println("=== end of query ==="); flightList.forEach(System.out::println); }}Copy the code

Query thread:

public class QueryThread implements Runnable{
    private CountDownLatch countDownLatch;
    private List<String> fightList=new ArrayList<>();
    private String name;

    public QueryThread(CountDownLatch countDownLatch,List<String> fightList, String name) {
        this.countDownLatch = countDownLatch;
        this.fightList=fightList;
        this.name = name;
    }

    @Override
    public void run(a) {
        int val=new Random().nextInt(10);
        try {
            System.out.printf("%s start query! \n",name);
            TimeUnit.SECONDS.sleep(val);
            fightList.add(name+"Vote:"+val);
            System.out.printf("%s query successful! \n",name);
            countDownLatch.countDown();
        }catch(Exception e){ e.printStackTrace(); }}}Copy the code

Execution code:

As can be seen from the execution result, after all three query threads complete the query, the main thread wakes up and returns the final data.

Through this example, we can conclude that if an interface depends on a number of third-party services or external interface, so if the serial call execution time will be long, this time can use CountDownLatch parallel calls, this idea is like using the message queue to decouple the upstream and downstream system process.

CyclicBarrier

Cyclicbarriers, which can be translated as “circular barriers,” enable a group of threads to wait until a state is reached before executing synchronously. The “loop” aspect is that cyclicBarriers can be reused once all waiting threads have been released.

The basic principle of execution is that when a thread calls the await() method of CyclicBarrier, it is in a barrier state, that is, it has encountered a barrier. If all threads execute to this state, the barrier opens, allowing all threads to continue down.

Let’s take a look at some important methods in common use, starting with constructors:

CyclicBarrier barrier=new CyclicBarrier(parties);
Copy the code

Parties are the number of participating threads.

Await () method:

barrier.await();
Copy the code

The thread calls this method to indicate that it has reached the fence.

Taking a race of five runners as an example, this process will not start until all the runners have reached the starting line, which fits the idea of a CyclicBarrier.

public class CyclicBarrierDemo {
    public static void main(String[] args) {
        CyclicBarrier barrier=new CyclicBarrier(5);
        Thread[] player=new Thread[5];
        for (int i = 0; i <5 ; i++) {
            player[i]=new Thread(()->{
                try {
                    TimeUnit.SECONDS.sleep(new Random().nextInt(10));
                    System.out.println(Thread.currentThread().getName()+" is ready");
                    barrier.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+" start running");
            },"player["+i+"]"); player[i].start(); }}}Copy the code

Execution code:

As you can see from the execution result, after all 5 threads have finished executing the await method, they continue to execute the subsequent code.

conclusion

Both CountDownLatch and CyclicBarrier have multiple threads waiting for synchronization before starting the next action, but there are several differences between them:

  • CountDownLatchIt needs to be called by the thread itselfcountDown()Method is reduced by one count and then called when all is doneawait()Methods; whileCyclicBarrierCall directlyawait()Method wait
  • CountDownLatchThe corresponding value is reduced by one;CyclicBarrierAdd one to the corresponding value
  • CountDownLatchIn the more cooperative case of multiple threads, when everything is ready, the waiting blocking thread will execute automatically;The CyclicBarrierAll threads block in one place until all threads are ready to execute together
  • CountDownLatchThe executor of the next action is the main thread; whileCyclicBarrierThe next action is performed by each child thread
  • CountDownLatchIt is not repeatable;CyclicBarrierWith the characteristics of repeated implementation of action, can be recycled

The last

If you think it is helpful, you can like it and forward it. Thank you very much

Public number agriculture ginseng, add a friend, do a thumbs-up friend ah