Java เห็นพ้องด้วย: Countdown latch vs Cyclic barrier


160

ฉันอ่านผ่านjava.util.concurrent APIและพบว่า

  • CountDownLatch: ตัวช่วยการซิงโครไนซ์ที่อนุญาตให้เธรดหนึ่งเธรดหรือมากกว่ารอจนกระทั่งชุดของการดำเนินการที่ดำเนินการในเธรดอื่นเสร็จสมบูรณ์
  • CyclicBarrier: เครื่องมือช่วยในการซิงโครไนซ์ที่อนุญาตให้ชุดของเธรดทั้งหมดรอให้กันและกันถึงจุดกีดขวางทั่วไป

สำหรับฉันทั้งคู่ดูเหมือนเท่ากัน แต่ฉันมั่นใจว่ามีมากกว่านั้น

CoundownLatch, the countdown value could not be reset, that can happen in the case of CyclicBarrierยกตัวอย่างเช่นใน

มีความแตกต่างอื่น ๆ ระหว่างสองหรือไม่
ใครบ้างuse casesที่ต้องการรีเซ็ตค่าการนับถอยหลัง


12
แลตช์ใช้สำหรับรอเหตุการณ์ อุปสรรคสำหรับรอหัวข้ออื่น ๆ - Java Concurrency ในทางปฏิบัติ, B.Goetz และคณะ
user2418306

คำตอบ:


137

ความแตกต่างที่สำคัญอย่างหนึ่งคือCyclicBarrierใช้งาน (เป็นทางเลือก) Runnable ซึ่งจะทำงานทันทีที่พบกับเงื่อนไขของสิ่งกีดขวาง

นอกจากนี้ยังช่วยให้คุณรับจำนวนลูกค้าที่รออยู่ที่สิ่งกีดขวางและจำนวนที่ต้องใช้เพื่อทริกเกอร์สิ่งกีดขวาง เมื่อถูกทริกเกอร์สิ่งกีดขวางจะถูกรีเซ็ตและสามารถใช้งานได้อีกครั้ง

สำหรับกรณีการใช้งานที่ง่าย - บริการเริ่มต้น ฯลฯ ... CountdownLatch นั้นใช้ได้ CyclicBarrier มีประโยชน์สำหรับการประสานงานที่ซับซ้อนมากขึ้น ตัวอย่างของสิ่งดังกล่าวจะเป็นแบบคู่ขนานการคำนวณ - ที่งานย่อยหลายมีส่วนร่วมในการคำนวณ - ชนิดเช่นMapReduce


6
"มันยังช่วยให้คุณรับจำนวนไคลเอนต์ที่รออยู่ที่สิ่งกีดขวางและจำนวนที่ต้องใช้เพื่อทริกเกอร์สิ่งกีดขวางเมื่อทริกเกอร์สิ่งกีดขวางจะถูกรีเซ็ตและสามารถใช้งานได้อีกครั้ง" ฉันชอบจุดนี้มาก บทความสองสามข้อที่ฉันได้อ่านแนะนำว่า CyclicBarrier เป็นวงจรเนื่องจากคุณเรียกใช้เมธอด reset () นั่นเป็นความจริง แต่สิ่งที่พวกเขาไม่ได้กล่าวถึงบ่อยครั้งก็คือสิ่งกีดขวางนั้นจะถูกรีเซ็ตโดยอัตโนมัติทันทีที่มันถูกทริกเกอร์ ฉันจะโพสต์โค้ดตัวอย่างเพื่ออธิบายสิ่งนี้
เควินลี

@Kevin Lee ขอบคุณสำหรับ "สิ่งกีดขวางนั้นถูกรีเซ็ตโดยอัตโนมัติทันทีที่มันถูกทริกเกอร์" ดังนั้นไม่จำเป็นต้องเรียกใช้รีเซ็ต () ในรหัส
ซูเปอร์โนวา

134

มีความแตกต่างอื่น

เมื่อใช้ a CyclicBarrierข้อสันนิษฐานคือคุณระบุจำนวนของเธรดการรอที่เรียกสิ่งกีดขวาง ถ้าคุณระบุ 5 คุณต้องมีอย่างน้อย 5 await()กระทู้ที่จะเรียก

เมื่อใช้ a CountDownLatchคุณระบุจำนวนการโทรcountDown()ที่จะส่งผลให้เธรดที่รออยู่ทั้งหมดถูกรีลีส ซึ่งหมายความว่าคุณสามารถใช้ a CountDownLatchด้วยเธรดเดียวเท่านั้น

"ทำไมคุณถึงทำอย่างนั้น" คุณอาจพูด ลองนึกภาพว่าคุณกำลังใช้ API ที่ลึกลับซึ่งเขียนขึ้นโดยบุคคลอื่นที่ดำเนินการติดต่อกลับ คุณต้องการให้หนึ่งในเธรดของคุณรอจนกว่าการเรียกกลับบางอย่างถูกเรียกหลายครั้ง คุณไม่ทราบว่าจะมีการโทรกลับหัวข้อใด ในกรณีนี้ a CountDownLatchสมบูรณ์แบบในขณะที่ฉันไม่สามารถคิดวิธีที่จะใช้สิ่งนี้โดยใช้CyclicBarrier(จริง ๆ แล้วฉันทำได้ แต่มันเกี่ยวข้องกับการหมดเวลา ... yuck!)

ฉันแค่หวังว่าCountDownLatchจะสามารถรีเซ็ตได้!


10
ฉันคิดว่านี่เป็นคำตอบที่แสดงความแตกต่างทางทฤษฎีได้ดีขึ้น ความจริงที่ว่า latches สามารถใช้งานไม่ได้โดยการเรียกวิธีการหลาย ๆ ครั้งในขณะที่สิ่งกีดขวางต้องใช้จำนวนเธรดที่แม่นยำในการรอ ()
flagg19

43
ถูกต้อง - นั่นคือความแตกต่างที่สำคัญ: CountDownLatch -> NumberOfCalls, CyclicBarrier -> NumberOfThreads
Ivan Voroshilin

1
ฉันยอมรับว่ามันจะดีสำหรับCountDownLatchการตั้งค่าใหม่ - วิธีแก้ปัญหาที่ฉันใช้ในการดำเนินการแจ้งให้ทราบอย่างคร่าวๆเป็นเพียงการสร้างขึ้นใหม่CountDownLatchทันทีเมื่อป้อนรหัสบล็อกที่มีการป้องกัน (เมื่อสลักถึงศูนย์) นี่ไม่สามารถใช้ได้ในทุกสถานการณ์ / ขอบเขตแน่นอน แต่ฉันคิดว่ามันน่าสังเกตว่ามันเป็นตัวเลือกในสถานการณ์ goldilocks
Ephemera

2
หนึ่งในคำตอบที่ดีที่สุดในหัวข้อนี้ Java Concurrency in Practice- พูดสิ่งเดียวกัน: Latches are for waiting for events; barriers are for waiting for other threads.. จุดหลักและจุดสำคัญที่จะเข้าใจความแตกต่างระหว่างสองสิ่งนี้
Rahul Dev Mishra

Java 8 doc กล่าวว่า "สามารถใช้ CountDownLatch ที่กำหนดค่าเริ่มต้นเป็น N เพื่อรอหนึ่งเธรดจนกว่าเธรด N จะเสร็จสิ้นการกระทำบางอย่างหรือการดำเนินการบางอย่างเสร็จสิ้น N ครั้ง" ดูเหมือนว่าฉัน: CountDownLatch -> NumberOfCalls หรือ CountDownLatch -> NumberOfThreads
พฤศจิกายน

41

ประเด็นหนึ่งที่ไม่มีใครได้กล่าวถึงคือในCyclicBarrierหัวข้อหากมีปัญหา (หมดเวลาขัดจังหวะ ... ) คนอื่น ๆ ทั้งหมดที่มาถึงawait()จะได้รับการยกเว้น ดู Javadoc:

CyclicBarrier ใช้โมเดลการแตกทั้งหมดหรือไม่มีเลยสำหรับความพยายามในการซิงโครไนซ์ที่ล้มเหลว: หากเธรดออกจากจุดกีดขวางก่อนเวลาอันควรเนื่องจากการขัดจังหวะความล้มเหลวหรือหมดเวลาเธรดอื่น ๆ ทั้งหมดที่รออยู่ที่จุดกีดขวางนั้น หากพวกเขาถูกขัดจังหวะในเวลาเดียวกัน)


22

ฉันคิดว่า JavaDoc ได้อธิบายความแตกต่างอย่างชัดเจน คนส่วนใหญ่รู้ว่า CountDownLatch ไม่สามารถรีเซ็ตได้อย่างไรก็ตาม CyclicBarrier สามารถ แต่นี่ไม่ใช่ความแตกต่างเท่านั้นหรือ CyclicBarrier สามารถเปลี่ยนชื่อเป็น ResetbleCountDownLatch เราควรบอกความแตกต่างจากมุมมองของเป้าหมายซึ่งอธิบายไว้ใน JavaDoc

CountDownLatch:ตัวช่วยการซิงโครไนซ์ที่อนุญาตให้เธรดตั้งแต่หนึ่งเธรดขึ้นไปรอจนกว่าชุดการดำเนินการที่ดำเนินการในเธรดอื่นจะเสร็จสิ้น

CyclicBarrier:ตัวช่วยการซิงโครไนซ์ที่อนุญาตให้ชุดของเธรดทั้งหมดรอให้กันและกันถึงจุดกีดขวางทั่วไป

ใน countDownLatch มีเธรดตั้งแต่หนึ่งเธรดขึ้นไปที่รอชุดของเธรดอื่นให้เสร็จสมบูรณ์ ในสถานการณ์นี้มีเธรดอยู่สองประเภทหนึ่งประเภทกำลังรออีกประเภทหนึ่งกำลังทำอะไรบางอย่างหลังจากทำภารกิจเสร็จสิ้นพวกเขาอาจรอหรือยุติการทำงาน

ใน CyclicBarrier มีเธรดเพียงชนิดเดียวพวกเขากำลังรอซึ่งกันและกันพวกเขาเท่ากัน


1
"ใน CyclicBarrier มีเธรดเพียงชนิดเดียว" ... พวกเขาเท่ากันใน "บทบาทการรอ" จนกว่าเธรดอื่นจะเรียกว่า. wait () แต่พวกเขาอาจจะ "ไม่เท่ากันในสิ่งที่พวกเขาทำ" พวกเขาทั้งหมดจะต้องเป็นอินสแตนซ์เธรดที่แตกต่างกันอย่างแน่นอน (!) ประเภทเดียวกันหรือต่างชนิดกันในขณะที่ใน CountDownLatch เธรดเดียวกันอาจเรียก countDown () และมีผลต่อผลลัพธ์
Vladimir Nabokov

ฉันยอมรับว่า CountDownLatch ต้องมีสองบทบาทโดยเนื้อแท้: ไคลเอนต์หนึ่งรายสำหรับ countDown และไคลเอนต์หนึ่งรอ ในทางกลับกันลูกค้า CyclicBarrier สามารถใช้งานได้ดีด้วยวิธีการที่รอคอย
isaolmez

14

ความแตกต่างหลักถูกบันทึกไว้ใน Javadocs สำหรับ CountdownLatch กล่าวคือ:

CountDownLatch เริ่มต้นได้ด้วยการนับที่กำหนด เมธอดที่รอจะบล็อกจนกว่าการนับปัจจุบันจะถึงศูนย์เนื่องจากการเรียกใช้เมธอด countDown () หลังจากที่เธรดการรอทั้งหมดถูกรีลีสและการเรียกใช้ที่ตามมาภายหลังของการรอคอยส่งคืนทันที นี่เป็นปรากฏการณ์ครั้งเดียว - การนับไม่สามารถรีเซ็ตได้ หากคุณต้องการเวอร์ชันที่รีเซ็ตการนับลองพิจารณาใช้ CyclicBarrier

แหล่งที่มา1.6 Javadoc


4
หากความแตกต่างของพวกเขาเป็นเพียงแค่สามารถรีเซ็ตหรือไม่ CyclicBarrier อาจจะดีกว่าชื่อ ResetableCountDownLatch ซึ่งมีความหมายมากขึ้นเนื่องจากความแตกต่าง
James.Xu

12

CountDownLatch ใช้สำหรับการซิงโครไนซ์ครั้งเดียว ในขณะที่ใช้งาน CountDownLatch เธรดใด ๆ ก็ได้รับอนุญาตให้เรียก countDown () หลาย ๆ ครั้งตามที่ต้องการ เธรดที่เรียกว่า await () จะถูกบล็อกจนกว่าจำนวนถึงศูนย์เนื่องจากการเรียกไปยัง countDown () โดยเธรดที่ไม่ถูกบล็อกอื่น ๆ Javadoc สำหรับ CountDownLatchฯ :

เมธอดที่รอจะบล็อกจนกว่าการนับปัจจุบันจะถึงศูนย์เนื่องจากการเรียกใช้เมธอด countDown () หลังจากที่เธรดการรอทั้งหมดถูกรีลีสและการเรียกใช้ที่ตามมาภายหลังของการรอคอยส่งคืนทันที ...

การใช้งานทั่วไปอื่น ๆ ก็คือการแบ่งปัญหาออกเป็นส่วนต่าง ๆ อธิบายแต่ละส่วนด้วย Runnable ที่ดำเนินการส่วนนั้นและนับถอยหลังบนสลักและคิว Runnables ทั้งหมดไปยังผู้บริหาร เมื่อทุกส่วนย่อยเสร็จสมบูรณ์เธรดการประสานงานจะสามารถผ่านรอ (เมื่อเธรดต้องนับซ้ำด้วยวิธีนี้ให้ใช้ CyclicBarrier แทน)

ในทางตรงกันข้าม cyclic barrier ใช้สำหรับจุด sychronization หลายจุดเช่นถ้าชุดของเธรดกำลังทำการคำนวณลูป / phased และจำเป็นต้องซิงโครไนซ์ก่อนเริ่มการทำซ้ำ / เฟสถัดไป ตามjavadoc สำหรับ CyclicBarrier :

สิ่งกีดขวางนั้นเรียกว่าวงจรเนื่องจากมันสามารถนำกลับมาใช้ใหม่ได้หลังจากปล่อยเธรดที่รออยู่

ต่างจาก CountDownLatch แต่ละการเรียกเพื่อรอ () เป็นของบางเฟสและสามารถทำให้เธรดปิดกั้นได้จนกว่าทุกฝ่ายที่อยู่ในเฟสนั้นจะเรียกใช้งานรอ () ไม่มีการดำเนินการ countDown () ที่ชัดเจนที่สนับสนุนโดย CyclicBarrier


12

คำถามนี้ได้รับคำตอบอย่างเพียงพอแล้ว แต่ฉันคิดว่าฉันสามารถเพิ่มมูลค่าได้เล็กน้อยโดยการโพสต์รหัส

เพื่อแสดงพฤติกรรมของสิ่งกีดขวางแบบวนรอบฉันได้สร้างโค้ดตัวอย่างบางส่วน ทันทีที่สิ่งกีดขวางถูกเอียงก็จะถูกรีเซ็ตโดยอัตโนมัติเพื่อให้สามารถใช้งานได้อีกครั้ง (จึงเป็น "วงจร") เมื่อคุณเรียกใช้โปรแกรมให้สังเกตว่าการพิมพ์ลึกหนาบาง "พิมพ์เล่น" จะถูกทริกเกอร์เฉพาะหลังจากสิ่งกีดขวางถูกทิป

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();
        }
    }
}

8

เมื่อฉันเรียนเกี่ยวกับแลตช์และไซโคลบาเรียร์ฉันก็นึกถึงคำอุปมาอุปมัยนี้ cyclicbarriers : ลองนึกภาพ บริษัท ที่มีห้องประชุม เพื่อเริ่มการประชุมผู้เข้าร่วมประชุมจำนวนหนึ่งต้องมาประชุม (เพื่อให้เป็นทางการ) ต่อไปนี้เป็นรหัสของผู้เข้าร่วมประชุมปกติ (พนักงาน)

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!!");
    }
 }
}

ในวันปกติพนักงานมาประชุมรอให้คนอื่นมาปรากฏตัวและหากผู้เข้าร่วมประชุมบางคนไม่มาพวกเขาต้องรออย่างไม่มีกำหนด! ในการประชุมพิเศษบางครั้งหัวหน้าจะมาและเขาไม่ชอบที่จะรอ (5 คนจำเป็นต้องเริ่มการประชุม แต่มีเพียงเจ้านายเท่านั้นที่มาพร้อมกับพนักงานที่กระตือรือร้น) ดังนั้นเขาจึงยกเลิกการประชุม (โกรธ)

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 ...");
 }
}

Latches : หากหัวหน้าโกรธต้องการจัดนิทรรศการสำหรับลูกค้า บริษัท ทุกสิ่งต้องพร้อม (ทรัพยากร) เราจัดทำรายการสิ่งที่ต้องทำทุกคน (ด้าย) งานของเขาและเราตรวจสอบรายการสิ่งที่ต้องทำ เมื่อทุกรายการในรายการสิ่งที่ต้องทำเสร็จสมบูรณ์ (มีการจัดหาทรัพยากร) เราสามารถเปิดประตูให้ลูกค้า

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();

7

สั้นเพียงเพื่อทำความเข้าใจความแตกต่างการทำงานที่สำคัญระหว่างสอง:

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();
        }
    }
}

ยกเว้นแน่นอนคุณสมบัติเช่นการไม่ปิดกั้นรอเวลาการวินิจฉัยและทุกอย่างที่ได้รับการอธิบายรายละเอียดในคำตอบข้างต้น

อย่างไรก็ตามคลาสที่กล่าวมาข้างต้นนั้นสามารถใช้งานได้อย่างสมบูรณ์และเทียบเท่าภายในฟังก์ชั่นที่มีให้กับผู้ที่มีชื่อเหมือนกัน

ในบันทึกย่อCountDownLatchอื่นคลาสย่อยของคลาสAQSในขณะที่CyclicBarrierใช้งานReentrantLock(ความสงสัยของฉันคือมันอาจเป็นวิธีอื่นหรือทั้งสองอย่างสามารถใช้ AQS หรือทั้งสองใช้ Lock - โดยไม่สูญเสียประสิทธิภาพการทำงาน)


5

ข้อแตกต่างที่ชัดเจนประการหนึ่งคือมีเพียง N เธรดเท่านั้นที่สามารถรอคอยใน CyclicBarrier of N ที่จะปล่อยในรอบเดียว แต่ไม่ จำกัด จำนวนเธรดที่สามารถรอได้บน CountDownLatch of N การลดจำนวนนับลงสามารถทำได้โดยหนึ่งเธรด N ครั้งหรือ N เธรดหนึ่งครั้งแต่ละครั้งหรือการรวมกัน


4

ในกรณีของ CyclicBarrier ทันทีที่เธรดลูกทั้งหมดเริ่มเรียก barrier.await () Runnable จะถูกดำเนินการใน Barrier สิ่งกีดขวางรอในเธรดลูกแต่ละรายการจะใช้เวลาที่แตกต่างกันในการจบเวลาและทั้งหมดจะเสร็จสิ้นในเวลาเดียวกัน


4

ในCountDownLatchเธรดหลักจะรอเธรดอื่นเพื่อดำเนินการให้เสร็จสมบูรณ์ ในCyclicBarrierเธรดผู้ปฏิบัติงานรอให้กันและกันเพื่อดำเนินการให้เสร็จสมบูรณ์

คุณไม่สามารถใช้อินสแตนซ์CountDownLatchเดียวกันอีกครั้งเมื่อจำนวนถึงศูนย์และเปิดสลักในอีกทางหนึ่งCyclicBarrierสามารถนำกลับมาใช้ใหม่ได้โดยการรีเซ็ต Barrier เมื่อกำแพงพัง


มันไม่จำเป็นต้องเป็นหัวข้อหลัก อาจเป็นเธรดใด ๆ ที่สร้าง CountDownLatch และแบ่งใช้กับเธรดอื่นที่ไม่ใช่หลัก
Aniket Thakur

1

CountDownLatch คือการนับถอยหลังของสิ่งใด CyclicBarrier เป็นการนับถอยหลังสำหรับเธรดเท่านั้น

สมมติว่ามี 5 หัวข้อผู้ปฏิบัติงานและหนึ่งผู้ส่งหัวข้อและเมื่อคนงานผลิต 100 รายการผู้ส่งจะจัดส่งพวกเขาออก

สำหรับ CountDownLatch ตัวนับสามารถทำงานกับพนักงานหรือไอเท็มได้

สำหรับ CyclicBarrier ตัวนับสามารถทำงานกับคนงานได้เท่านั้น

หากผู้ปฏิบัติงานนอนหลับไม่ จำกัด ด้วย CountDownLatch บนไอเท็มผู้ขนส่งสามารถจัดส่งได้ อย่างไรก็ตามด้วย CyclicBarrier ทำให้ไม่สามารถเรียกผู้ส่งได้


0

@Kevin Lee และ @Jon ฉันลอง CyclicBarrier ด้วยตัวเลือก Runnable ดูเหมือนว่ามันจะทำงานในตอนเริ่มต้นและหลังจาก CyclicBarrier ถูกปลาย นี่คือรหัสและผลลัพธ์

อุปสรรค CyclicBarrier คงที่;

    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.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.