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.(其它线程完成一些操作,但不等于这些线程要结束,也要不结束)

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()前执行,等待其他线程写入完毕

 

时间: 2024-10-30 23:28:33

CountDownLatch和CyclicBarrier 专题的相关文章

Java并发编程:CountDownLatch、CyclicBarrier和Semaphore

在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch,CyclicBarrier和Semaphore,今天我们就来学习一下这三个辅助类的用法. 以下是本文目录大纲: 一.CountDownLatch用法 二.CyclicBarrier用法 三.Semaphore用法 若有不正之处请多多谅解,并欢迎批评指正. 请尊重作者劳动成果,转载请标明原文链接: http://www.cnblogs.com/dolphin0520/p/3920397.htm

java-并发-CountDownLatch、CyclicBarrier和Semaphore

在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch,CyclicBarrier和Semaphore,今天我们就来学习一下这三个辅助类的用法. 以下是本文目录大纲: 一.CountDownLatch用法 二.CyclicBarrier用法 三.Semaphore用法 若有不正之处请多多谅解,并欢迎批评指正. 请尊重作者劳动成果,转载请标明原文链接: http://www.cnblogs.com/dolphin0520/p/3920397.htm

弱弱的问一句CountDownLatch与CyclicBarrier的区别

问题描述 我知道 CountDownLatch使一个或多个线程等待其他线程,CylicBarrier使所有线程相互等待但是完全可以使用CountDownLatch替代CyliBarrier的啊package Thread;import java.util.concurrent.CountDownLatch;import java.util.concurrent.TimeUnit;public class line3 implements Runnable{private CountDownLat

Java中多线程处理的CountDownLatch和CyclicBarrier教程

CountDownLatch 字面意思就是倒计数闩,后面会讲到,这里的同步允许一个或多个线程等待,,知道其他线程进行的一系列操作完成.而CountDownLatch通过一个参数count(数目)来构造,而await()则阻塞当前线程,直到countDown()将count减为了0,然后,所有的阻塞线程被释放,也就是那些调用了await方法的线程立即返回,注意,这是一次性的,也就是说count不能被自动重置,如果你想这么做,CyclicBarrier是可以的. CountDownLatch用处很多

详解Java多线程编程中CountDownLatch阻塞线程的方法_java

直译过来就是倒计数(CountDown)门闩(Latch).倒计数不用说,门闩的意思顾名思义就是阻止前进.在这里就是指 CountDownLatch.await() 方法在倒计数为0之前会阻塞当前线程. CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待. CountDownLatch 的作用和 Thread.join() 方法类似,可用于一组线程和另外一组线程的协作.例如,主线程在做一项工作之前需要一系列的准备工作,只有这些准备工

Java多线程:“JUC锁”01之框架

根据锁的添加到Java中的时间,Java中的锁,可以分为"同步锁"和 "JUC包中的锁". 同步锁 即通过synchronized关键字来进行同步,实现对竞争资源的互斥访问的锁.Java 1.0版本中就已经支 持同步锁了. 同步锁的原理是,对于每一个对象,有且仅有一个同步锁:不同的线程能共同访问该同步锁.但是, 在同一个时间点,该同步锁能且只能被一个线程获取到.这样,获取到同步锁的线程就能进行CPU调度, 从而在CPU上执行:而没有获取到同步锁的线程,必须进行等待,

深入Guava源码之Stripe

当前JDK对并发编程的支持 Sun在Java5中引入了concurrent包,它对Java的并发编程提供了强大的支持.首先,它提供了Lock接口,可用了更细粒度的控制锁的区域,它的实现类有ReentrantLock,ReadLock,WriteLock,其中ReadLock和WriteLock共同用于实现ReetrantReadWriteLock(它继承自ReadWriteLock,但是没有实现Lock接口,ReadWriteLock接口也没有继承Lock接口).而且,它还提供了一些常用并发场景

Java线程面试题 Top 50

不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java语言一个重要的特点就是内置了对并发的支持,让Java大受企业和程序员 的欢迎.大多数待遇丰厚的Java开发职位都要求开发者精通多线程技术并且有丰富的Java程序开发.调试.优化经验,所以线程相关的问题在面试中经常会 被提到. 在典型的Java面试中, 面试官会从线程的基本概念问起, 如:为什么你需要使用线程, 如何创建线程,用什么方式创建线程比较好(比如:继承thread类还是调用Runnable接口),然后逐渐问到并发问题像

Java你不得不看的十本书,进阶

10本书在Java程序员界都是被认为很棒的书.当一个程序员开始初学Java时,他的第一个问题应该是如何选择一本书来作为指导学习Java.这个问题也就表明,相对于其他的教程和博客,Java书籍还是很重要的参考,主要表现在以下两点: 通常书籍是由比较权威的程序员来撰写的.相比其他媒介,书籍对于内容的描述更加详细,解释更加明确. 1.Head First Java Head First Java是所有编程或者Java初学者最适合的书籍,我很喜欢轻松和寓教于乐的Head First风格,这应该是最有意思