CountDownLatch和CyclicBarrier 专题

简介: javadoc里面的描述是这样的。 CountDownLatch: A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

javadoc里面的描述是这样的。

CountDownLatch: A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.(其它线程完成一些操作,但不等于这些线程要结束,也要不结束)

CyclicBarrier : A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point.

可能是我的英语不够好吧, 我感觉从这个javadoc里面要准确理解他们的差异还是不容易的。
我的理解是

CountDownLatch: 一个线程(或者多个), 等待另外N个线程完成某个事情之后才能执行。
CyclicBarrier: N个线程相互等待,只要有任何一个线程没有完成,其它的N-1个线程都必须等待。
这样应该就清楚一点了,
对于CountDownLatch来说,重点是那个“一个线程, 是它在等待, 而另外那N的线程在把“某个事情”做完之后可以继续等待,可以终止

而对于CyclicBarrier来说,重点是那N个线程,他们之间任何一个没有完成,所有的线程都必须等待。

 

CountDownLatch 是计数器, 线程完成一个就记一个, 就像 报数一样, 只不过是递减的.

而CyclicBarrier更像一个水闸, 线程执行就想水流, 在水闸处都会堵住, 等到水满(线程到齐)了, 才开始泄流.

在网上看到很多人对于CountDownLatch和CyclicBarrier的区别简单理解为CountDownLatch是一次性的(因为整个流程已经完成了,不需要再来一次,所以一次性),而CyclicBarrier在调用reset之后还可以继续使用。那如果只是这么简单的话,我觉得CyclicBarrier简单命名为ResetableCountDownLatch好了,显然不是的。
上面是从设计目的去看这两个类。

http://blog.csdn.net/kjfcpua/article/details/7300286

 

用法:

一、CountDownLatch用法

  CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能。比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了。

  CountDownLatch类只提供了一个构造器:

public CountDownLatch(int count) { }; //参数count为计数值

  然后下面这3个方法是CountDownLatch类中最重要的方法:

public void await() throws InterruptedException { };
//调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };
//和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
public void countDown() { }; //将count值减1

 

二、CyclicBarrier用法

  通过它可以实现让一组线程等待至某个状态之后再全部同时执行,并且当所有等待线程都被释放以后,CyclicBarrier还可以被重用。我们暂且把这个状态就叫做barrier,当调用await()方法之后,线程就处于barrier了。

  CyclicBarrier类位于java.util.concurrent包下,CyclicBarrier提供2个构造器:

public CyclicBarrier(int parties, Runnable barrierAction) {
}
 
public CyclicBarrier(int parties) {
}

  参数parties指定让多少个线程或者任务等待至barrier状态;参数barrierAction为当这些线程都达到barrier状态时会执行的内容。

  然后CyclicBarrier中最重要的方法就是await方法,它有2个重载版本:

public int await() throws InterruptedException, BrokenBarrierException { };
public int await(long timeout, TimeUnit unit)throws InterruptedException,BrokenBarrierException,TimeoutException { };

  第一个版本比较常用,用来挂起当前线程,直至所有线程都到达barrier状态再同时执行后续任务;

  第二个版本是让这些线程等待至一定的时间,如果还有线程没有到达barrier状态就直接让到达barrier的线程执行后续任务。

http://www.cnblogs.com/codeOfLife/p/5687691.html

 

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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

public class CyclicBarrierDemo {
    private static final Logger LOGGER = LoggerFactory.getLogger(CyclicBarrierDemo.class);

    public static void main(String[] args) throws InterruptedException {

        int parties = 4;
        int count = parties + 1;
        CountDownLatch startGate = new CountDownLatch(count);
        CyclicBarrier barrier = new CyclicBarrier(parties);
        for (int i = 0; i < parties; i++) {
            Thread thread = new Thread(new Writer(barrier, startGate), "demo" + i);
            thread.start();
        }

        LOGGER.info(" ");
        int timeout = 6;
        LOGGER.info("主线程 还需要再阻塞{}s",timeout);
        new Thread(() -> {
            try {
                LOGGER.info("现在开始{}s等待。 CountDownLatch才允许主线程结束阻塞状态",timeout);
                TimeUnit.SECONDS.sleep(timeout);
                startGate.countDown();
                LOGGER.info("{}s等待结束.主线程可以往下走了",timeout);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        startGate.await();//当前线程(main线程)被阻塞,直到startGate的countDown方法的次数和设定的值相同,其它的不要求

        LOGGER.info("====不管Writer线程是否完成,只要countDown的调用次数够了,CountDownLatch就会解除主线程的阻塞状态====");
        LOGGER.info(" ");
        TimeUnit.SECONDS.sleep(10);
        LOGGER.info(" ");
        LOGGER.info("======================CyclicBarrier的可重用性开始======================");
        LOGGER.info(" ");
        int lessParties = parties - 1;
        for (int i = 0; i < lessParties; i++) {
            Thread thread = new Thread(new Writer(barrier, startGate), "damo" + (i + parties));
            thread.start();
        }
        startGate.await();//不会阻塞主线程运行,但write线程会执行不完
        LOGGER.info("目前只调用{}次countDown,虽然小于设置的count {},但仍然不会阻塞主线程",lessParties,count);
        LOGGER.info("CyclicBarrier仍然需要{}个线程都至barrier状态,否则相关的Write线程都需要阻塞。目前只有{}个parties。" +
                "\n 因此所有的Writer线程会一起阻塞下去forever until server shutdown",parties,lessParties);
    }

    static class Writer implements Runnable {
        private CyclicBarrier cyclicBarrier;
        private CountDownLatch startGate;

        Writer(CyclicBarrier cyclicBarrier, CountDownLatch startGate) {
            this.cyclicBarrier = cyclicBarrier;
            this.startGate = startGate;
        }

        @Override
        public void run() {
            try {
                startGate.countDown();
                LOGGER.info("线程" + Thread.currentThread().getName() + "cyclicBarrier.await()前执行,等待其他线程写入完毕");
                cyclicBarrier.await();
                TimeUnit.SECONDS.sleep(10);//sleep一会。这样日志中可以很好的看到cyclicBarrier.await()的可重用性r
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
            LOGGER.info(Thread.currentThread().getName() + "cyclicBarrier.await()后执行......");
        }
    }

}

 

Output:

22:15:31.632 [demo0] INFO CyclicBarrierDemo - 线程demo0cyclicBarrier.await()前执行,等待其他线程写入完毕
22:15:31.632 [demo3] INFO CyclicBarrierDemo - 线程demo3cyclicBarrier.await()前执行,等待其他线程写入完毕
22:15:31.632 [demo2] INFO CyclicBarrierDemo - 线程demo2cyclicBarrier.await()前执行,等待其他线程写入完毕
22:15:31.632 [demo1] INFO CyclicBarrierDemo - 线程demo1cyclicBarrier.await()前执行,等待其他线程写入完毕
22:15:31.632 [main] INFO CyclicBarrierDemo -  
22:15:31.637 [main] INFO CyclicBarrierDemo - 主线程 还需要再阻塞6s
22:15:31.763 [Thread-0] INFO CyclicBarrierDemo - 现在开始6s等待。 CountDownLatch才允许主线程结束阻塞状态
22:15:37.765 [main] INFO CyclicBarrierDemo - ====不管Writer线程是否完成,只要countDown的调用次数够了,CountDownLatch就会解除主线程的阻塞状态====
22:15:37.765 [main] INFO CyclicBarrierDemo -  
22:15:37.765 [Thread-0] INFO CyclicBarrierDemo - 6s等待结束.主线程可以往下走了
22:15:41.638 [demo3] INFO CyclicBarrierDemo - demo3cyclicBarrier.await()后执行......
22:15:41.638 [demo2] INFO CyclicBarrierDemo - demo2cyclicBarrier.await()后执行......
22:15:41.638 [demo0] INFO CyclicBarrierDemo - demo0cyclicBarrier.await()后执行......
22:15:41.638 [demo1] INFO CyclicBarrierDemo - demo1cyclicBarrier.await()后执行......
22:15:47.765 [main] INFO CyclicBarrierDemo -  
22:15:47.765 [main] INFO CyclicBarrierDemo - CyclicBarrier的可重用性开始:
22:15:47.765 [main] INFO CyclicBarrierDemo -  
22:15:47.765 [main] INFO CyclicBarrierDemo - 目前只调用3次countDown,虽然小于设置的count 5,但仍然不会阻塞主线程
22:15:47.765 [main] INFO CyclicBarrierDemo - 但CyclicBarrier仍然需要4个线程都至barrier状态。目前只有3个parties。
 因此所有的Writer线程会一起阻塞下去forever until server shutdown
22:15:47.765 [damo4] INFO CyclicBarrierDemo - 线程damo4cyclicBarrier.await()前执行,等待其他线程写入完毕
22:15:47.766 [damo5] INFO CyclicBarrierDemo - 线程damo5cyclicBarrier.await()前执行,等待其他线程写入完毕
22:15:47.766 [damo6] INFO CyclicBarrierDemo - 线程damo6cyclicBarrier.await()前执行,等待其他线程写入完毕

 

相关文章
|
8月前
|
Java BI
CountDownLatch,CyclicBarrier,Semaphore
在开发过程中我们常常遇到需要对多个任务进行汇总,比如报表,或者大屏显示,需要将所有接口的数据都 获取到后再进行汇总,如果使用同步的方式,那么会比较耗时,体验不好,所以我们使用多线程,但是使用多线程 只能异步的执行,有些接口响应比较快,有些比较慢,而返回结果之间又有依赖,这样就无法汇总了, 所以我们引入了CountDownLatch,它能让所有子线程全部执行完毕后主线程才会往下执行,如果子线程没有执行完毕 ,那么主线程将无法继续向下执行。
39 0
|
4月前
CountDownLatch和CyclicBarrier你使用过吗?
CountDownLatch和CyclicBarrier你使用过吗?
25 0
|
9月前
CountDownLatch 使用详解
本文主要对CountDownLatch 的相关知识点进行了介绍和讲解
73 1
|
9月前
CyclicBarrier 使用详解
本文主要对CyclicBarrier的相关知识点进行了介绍和讲解
115 0
CountDownLatch和 CyclicBarrier的使用
CountDownLatch和 CyclicBarrier的使用
CountDownLatch、CyclicBarrier的使用(门栓)
CountDownLatch、CyclicBarrier的使用(门栓)
87 0
CountDownLatch&CyclicBarrier&Semaphore
本文将介绍一下CountDownLatch 、 CyclicBarrier 、 Semaphore这几个控制线程的类。
 CountDownLatch&CyclicBarrier&Semaphore
CountDownLatch
CountDownLatch是从JDK1.5开始提供的一个辅助并发编程的一个类,它位于在JUC包中。 允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。
117 0
|
Java
CountDownLatch:别浪,等人齐再团!(1)
CountDownLatch:别浪,等人齐再团!(1)
93 0
|
Java
CountDownLatch:别浪,等人齐再团!(2)
CountDownLatch:别浪,等人齐再团!(2)
84 0
CountDownLatch:别浪,等人齐再团!(2)