Java并发:倒计时锁存器与循环屏障

Java并发:倒计时锁存器与循环屏障,java,concurrency,countdownlatch,cyclicbarrier,Java,Concurrency,Countdownlatch,Cyclicbarrier,我读了一遍,发现 CountDownLatch:一种同步辅助工具,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成 CyclicBarrier:一种同步辅助工具,允许一组线程都等待对方到达一个公共屏障点 对我来说,两者似乎是平等的,但我相信还有更多 例如,在ConcountDownLatch中,无法重置倒计时值,这可能发生在CyclicBarrier的情况下 这两者之间还有什么区别吗? 有人希望重置倒计时值的用例是什么?一个主要区别是,一旦满足公共屏障条件,就会执行(可选)可运行任

我读了一遍,发现

  • CountDownLatch
    :一种同步辅助工具,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成
  • CyclicBarrier
    :一种同步辅助工具,允许一组线程都等待对方到达一个公共屏障点
对我来说,两者似乎是平等的,但我相信还有更多

例如,在<代码>ConcountDownLatch中,无法重置倒计时值,这可能发生在CyclicBarrier的情况下

这两者之间还有什么区别吗?

有人希望重置倒计时值的
用例是什么?

一个主要区别是,一旦满足公共屏障条件,就会执行(可选)可运行任务


它还允许您获取在屏障处等待的客户端数量以及触发屏障所需的数量。一旦触发,安全栅将复位并可再次使用


对于简单用例-服务启动等。。。倒计时可以。自行车手对于更复杂的协调任务很有用。这种情况的一个例子是并行计算——计算中涉及多个子任务——有点类似。

主要区别就记录在Javadocs for CountdownLatch中。即:

倒计时锁存器是用 数一数。等待方法块 直到当前计数达到零为止 由于调用倒计时() 方法,之后所有 线程被释放,任何 等待返回的后续调用 马上。这是一次性的 现象——计数不能为空 重置。如果你需要一个版本 重置计数,考虑使用 骑自行车的人


来源

还有另一个区别

使用
CyclicBarrier
时,假设您指定触发屏障的等待线程数。如果指定5,则必须至少有5个线程可调用
await()

使用
CountDownLatch
时,指定将导致释放所有等待线程的
countDown()
调用次数。这意味着您可以仅使用单个线程来使用
倒计时闩锁

“你为什么要那样做?”,你可能会说。假设您正在使用由其他人编写的神秘API执行回调。您希望其中一个线程等待某个回调被调用多次。您不知道回调将在哪些线程上调用。在这种情况下,
countdownlock
是完美的,而我想不出任何方法来使用
CyclicBarrier
实现这一点(实际上,我可以,但它涉及超时……糟糕!)


我只希望
倒计时闩锁
可以重置

对于CyclicBarrier,只要所有子线程开始调用barrier.await(),就会在barrier中执行Runnable。每个子线程中的barrier.wait将花费不同的时间来完成,并且它们都同时完成

倒计时锁存器用于一次性同步。在使用CountDownLatch时,允许任何线程调用countDown()任意次数。调用wait()的线程将被阻止,直到计数达到零,因为其他未阻止的线程调用了countDown()。各国:

等待方法阻塞,直到当前计数由于以下原因达到零 调用countDown()方法,之后所有等待的线程 以及任何后续的等待返回调用 马上。

另一个典型用法是将问题分成N个部分, 使用执行该部分的Runnable描述每个部分,并 对闩锁进行倒计时,并将所有可运行项排队给执行器。 当所有子零件完成时,协调螺纹将能够 通过等待。(当线程必须在中重复倒计时时) 这样,就可以使用自行车马车。)

相反,循环屏障用于多个同步点,例如,如果一组线程正在运行循环/分阶段计算,并且需要在开始下一个迭代/阶段之前进行同步。根据:

这种屏障被称为循环屏障,因为它可以在碰撞后重新使用 等待的线程被释放


与CountDownLatch不同,对wait()的每个调用都属于某个阶段,并且会导致线程阻塞,直到属于该阶段的所有各方都调用了wait()。CyclicBarrier不支持显式倒计时()操作。

还没有人提到的一点是,在
CyclicBarrier
中,如果一个线程出现问题(超时、中断…),则到达
wait()
的所有其他线程都会出现异常。见Javadoc:

CyclicBarrier对失败的同步尝试使用“全部”或“无”中断模型:如果一个线程由于中断、故障或超时而过早离开某个屏障点,则在该屏障点等待的所有其他线程也将通过BrokenBarrierException异常离开(如果它们也在大约同一时间被中断,则为InterruptedException)


这个问题已经得到了充分的回答,但我认为我可以通过发布一些代码来增加一些价值

为了说明循环屏障的行为,我制作了一些示例代码。一旦屏障倾斜,它就会自动重置,以便可以再次使用(因此它是“循环的”)。当您运行程序时,请注意打印输出“Let's play”仅在屏障倾斜后才触发

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

public class CyclicBarrierCycles {

    static CyclicBarrier barrier;

    public static void main(String[] args) throws InterruptedException {
        barrier = new CyclicBarrier(3); 

        new Worker().start();
        Thread.sleep(1000);
        new Worker().start();
        Thread.sleep(1000);
        new Worker().start();
        Thread.sleep(1000);

        System.out.println("Barrier automatically resets.");

        new Worker().start();
        Thread.sleep(1000);
        new Worker().start();
        Thread.sleep(1000);
        new Worker().start();
    }

}


class Worker extends Thread {
    @Override
    public void run() {
        try {
            CyclicBarrierCycles.barrier.await();
            System.out.println("Let's play.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }
}

我认为JavaDoc已经明确地解释了这些差异。 大多数人都知道倒计时锁存器不能重置,但是CyclicBarrier可以。但这不是唯一的区别,或者CyclicBarrier可以重置
public class CountDownLatch {
    private Object mutex = new Object();
    private int count;

    public CountDownLatch(int count) {
        this.count = count;
    }

    public void await() throws InterruptedException {
        synchronized (mutex) {
            while (count > 0) {
                mutex.wait();
            }
        }
    }

    public void countDown() {
        synchronized (mutex) {
            if (--count == 0)
                mutex.notifyAll();
        }

    }
}
public class CyclicBarrier {
    private Object mutex = new Object();
    private int count;

    public CyclicBarrier(int count) {
        this.count = count;
    }

    public void await() throws InterruptedException {
        synchronized (mutex) {
            count--;
            while(count > 0)
                mutex.wait();
            mutex.notifyAll();
        }
    }
}
class MeetingAtendee implements Runnable {

CyclicBarrier myMeetingQuorumBarrier;

public MeetingAtendee(CyclicBarrier myMileStoneBarrier) {
    this.myMeetingQuorumBarrier = myMileStoneBarrier;
}

@Override
public void run() {
    try {
        System.out.println(Thread.currentThread().getName() + " i joined the meeting ...");
        myMeetingQuorumBarrier.await();
        System.out.println(Thread.currentThread().getName()+" finally meeting stared ...");
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (BrokenBarrierException e) {
        System.out.println("Meeting canceled! every body dance <by chic band!>");
    }
 }
}
class MeetingAtendeeTheBoss implements Runnable {

CyclicBarrier myMeetingQuorumBarrier;

public MeetingAtendeeTheBoss(CyclicBarrier myMileStoneBarrier) {
    this.myMeetingQuorumBarrier = myMileStoneBarrier;
}

@Override
public void run() {
    try {
        System.out.println(Thread.currentThread().getName() + "I am THE BOSS - i joined the meeting ...");
        //boss dose not like to wait too much!! he/she waits for 2 seconds and we END the meeting
        myMeetingQuorumBarrier.await(1,TimeUnit.SECONDS);
        System.out.println(Thread.currentThread().getName()+" finally meeting stared ...");
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (BrokenBarrierException e) {
        System.out.println("what WHO canceled The meeting");
    } catch (TimeoutException e) {
        System.out.println("These employees waste my time!!");
    }
 }
}
CyclicBarrier meetingAtendeeQuorum = new CyclicBarrier(5);
Thread atendeeThread = new Thread(new MeetingAtendee(meetingAtendeeQuorum));
Thread atendeeThreadBoss = new Thread(new MeetingAtendeeTheBoss(meetingAtendeeQuorum));
    atendeeThread.start();
    atendeeThreadBoss.start();
//Thread-1I am THE BOSS - i joined the meeting ...
// Thread-0 i joined the meeting ...
// These employees waste my time!!
// Meeting canceled! every body dance <by chic band!>
class NaturalDisasters implements Runnable {

CyclicBarrier someStupidMeetingAtendeeQuorum;

public NaturalDisasters(CyclicBarrier someStupidMeetingAtendeeQuorum) {
    this.someStupidMeetingAtendeeQuorum = someStupidMeetingAtendeeQuorum;
}

void earthQuakeHappening(){
    System.out.println("earth quaking.....");
    someStupidMeetingAtendeeQuorum.reset();
}

@Override
public void run() {
    earthQuakeHappening();
 }
}
// Thread-1I am THE BOSS - i joined the meeting ...
// Thread-0 i joined the meeting ...
// earth quaking.....
// what WHO canceled The meeting
// Meeting canceled! every body dance <by chic band!>
class MeetingSecretary implements Runnable {

@Override
public void run() {
        System.out.println("preparing meeting documents");
        System.out.println("taking notes ...");
 }
}
public class Visitor implements Runnable{

CountDownLatch exhibitonDoorlatch = null;

public Visitor (CountDownLatch latch) {
    exhibitonDoorlatch  = latch;
}

public void run() {
    try {
        exhibitonDoorlatch .await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    System.out.println("customer visiting exebition");
 }
}
class Worker implements Runnable {

CountDownLatch myTodoItem = null;

public Worker(CountDownLatch latch) {
    this.myTodoItem = latch;
}

public void run() {
        System.out.println("doing my part of job ...");
        System.out.println("My work is done! remove it from todo list");
        myTodoItem.countDown();
 }
}

    CountDownLatch preperationTodoList = new CountDownLatch(3);

    // exhibition preparation workers  
    Worker      electricalWorker      = new Worker(preperationTodoList);
    Worker      paintingWorker      = new Worker(preperationTodoList);

    // Exhibition Visitors 
    ExhibitionVisitor exhibitionVisitorA = new ExhibitionVisitor(preperationTodoList);
    ExhibitionVisitor exhibitionVisitorB = new ExhibitionVisitor(preperationTodoList);
    ExhibitionVisitor exhibitionVisitorC = new ExhibitionVisitor(preperationTodoList);

    new Thread(electricalWorker).start();
    new Thread(paintingWorker).start();

    new Thread(exhibitionVisitorA).start();
    new Thread(exhibitionVisitorB).start();
    new Thread(exhibitionVisitorC).start();
    public static void main(String[] args) throws InterruptedException {
        barrier = new CyclicBarrier(3, new Runnable() {
            @Override
            public void run() {
                System.out.println("I run in the beginning and after the CyclicBarrier is tipped");
            }
        });

        new Worker().start();
        Thread.sleep(1000);
        new Worker().start();
        Thread.sleep(1000);
        new Worker().start();
        Thread.sleep(1000);

        System.out.println("Barrier automatically resets.");

        new Worker().start();
        Thread.sleep(1000);
        new Worker().start();
        Thread.sleep(1000);
        new Worker().start();
    }
I run in the beginning and after the CyclicBarrier is tipped
Let's play.
Let's play.
Let's play.
Barrier automatically resets.
I run in the beginning and after the CyclicBarrier is tipped
Let's play.
Let's play.
Let's play.