programing

Java 동시성: 카운트다운 래치 vs 사이클 장벽

goodcopy 2022. 8. 8. 15:45
반응형

Java 동시성: 카운트다운 래치 vs 사이클 장벽

java.util.concurrent API를 읽다가

  • CountDownLatch: 1개 이상의 스레드가 다른 스레드에서 수행 중인 일련의 작업이 완료될 때까지 대기할 수 있는 동기화 보조 도구입니다.
  • CyclicBarrier: 포인트에 할 수 하는 장치 일련의 스레드가 공통의 장벽 포인트에 도달할 때까지 서로 대기할 수 있도록 하는 동기 보조 장치.

내게는 둘 다 동등해 보이지만, 그것에는 훨씬 더 많은 것이 있다고 확신한다.

를 들어, 「 」에서는,CoundownLatch, the countdown value could not be reset, that can happen in the case of CyclicBarrier

아, 네, 네.
□□□□□□가 뭐예요?use cases운운운운운운운운운운운운운운운?

또 다른 차이점이 있습니다.

「」를하고 있는 경우CyclicBarrier는 장벽을 트리거하는 대기 스레드 수를 지정하는 것을 전제로 하고 있습니다.를 호출하려면 .await().

「」를하고 있는 경우CountDownLatchcountDown()모든 대기 스레드가 해제됩니다., ,, 이, 를 사용할 수 있습니다.CountDownLatch아, 아, 네.

'어디로요?'콜백을 실행하는 다른 사용자가 코드화한 알 수 없는 API를 사용하고 있다고 가정합니다.특정 콜백이 여러 번 호출될 때까지 스레드 중 하나가 대기해야 합니다.콜백이 호출되는 스레드는 알 수 없습니다. 경우, 「」는,CountDownLatch 저는 이것을 할지 전혀 않습니다.CyclicBarrier★★★★★★★★★★★★★★★★★★」

나는 그저 바란다.CountDownLatch셋할! !!!!!!!!

주요 차이점은 CyclicBarrier가 공통 장벽 조건이 충족되면 실행되는 (옵션) Runnable 태스크를 수행한다는 것입니다.

또한 장벽에서 대기하는 클라이언트 수와 장벽을 트리거하는 데 필요한 수를 얻을 수 있습니다.트리거되면 장벽이 재설정되어 다시 사용할 수 있습니다.

단순한 사용 사례 - 서비스 시작 등...CountdownLatch도 괜찮습니다.CyclicBarrier는 보다 복잡한 조정 작업에 유용합니다.그러한 것의 예로는 병렬 계산(MapReduce와 같은 여러 서브태스크가 계산에 관여하는 경우)이 있습니다.

한 포인트는, 「아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아!CyclicBarrier가 있는 , 그 이 에 await() 참조: "Javadoc:

CyclicBarrier는 실패한 동기화 시행에 대해 모두 또는 전혀 중단 모델을 사용합니다.중단, 장애 또는 타임아웃으로 인해 스레드가 장벽 포인트를 너무 빨리 벗어나면 해당 장벽 포인트에서 대기하고 있는 다른 모든 스레드도 BrokenBarrier를 통해 비정상적으로 남습니다.예외(또는 중단됨)동시에 인터럽트된 경우는 예외).

자바독은 그 차이를 명확하게 설명했다고 생각합니다.대부분의 사람들은 CountDownLatch가 리셋되지 않는다는 것을 알고 있지만 CyclicBarrier는 리셋할 수 있습니다.그러나 이것만이 유일한 차이는 아닙니다.CyclicBarrier의 이름을 ResetbleCountDownLatch로 변경할 수 있습니다.JavaDoc에 기재되어 있는 목표의 관점에서 차이를 파악해야 합니다.

Count Down Latch: 다른 스레드에서 수행 중인 일련의 작업이 완료될 때까지 1개 이상의 스레드를 대기시킬 수 있는 동기화 보조 도구입니다.

CyclicBarrier:스레드 집합이 공통 장벽 지점에 도달할 때까지 서로 대기할 수 있도록 하는 동기화 보조 장치입니다.

countDownLatch에는 다른 스레드 집합이 완료되기를 기다리는 스레드가 하나 이상 있습니다.이 경우 스레드에는 두 가지 유형이 있습니다.하나는 대기 중이고 다른 하나는 작업을 수행하고 있습니다.작업이 종료된 후 스레드는 대기 중이거나 종료되었을 수 있습니다.

CyclicBarrier에는 스레드 유형이1개밖에 없습니다.이러한 스레드는 서로 대기하며 동등합니다.

주요 차이점은 Countdown Latch의 Javadocs에서 바로 확인할 수 있습니다.즉,

CountDownLatch는 지정된 카운트로 초기화됩니다.wait 메서드는 countDown() 메서드의 호출로 인해 현재 카운트가 0이 될 때까지 차단합니다.그 후 모든 대기 스레드가 해방되고 이후의 모든 호출이 즉시 반환됩니다.이것은 원샷 현상입니다.카운트는 리셋 할 수 없습니다.카운트를 리셋하는 버전이 필요한 경우는, CyclicBarrier 의 사용을 검토해 주세요.

소스 1.6 자바독

CountDownLatch는 일회성 동기화에 사용됩니다.CountDownLatch를 사용하는 동안 임의의 스레드는 원하는 횟수만큼 countDown()을 호출할 수 있습니다.wait()를 호출한 스레드는 차단되지 않은 다른 스레드에서 countDown()에 대한 호출로 인해 카운트가 0이 될 때까지 차단됩니다.CountDownLatch의 javadoc 상태는 다음과 같습니다.

wait 메서드는 countDown() 메서드의 호출로 인해 현재 카운트가 0이 될 때까지 차단합니다.그 후 모든 대기 스레드가 해방되고 이후의 모든 호출이 즉시 반환됩니다....

또 하나의 일반적인 사용법은 문제를 N개의 파트로 분할하여 각 파트를 Runnable로 기술하고, Runnables를 모두 실행자에게 큐잉하는 것입니다.모든 하위 부품이 완료되면 조정 스레드가 대기 상태를 통과할 수 있습니다.(이 방법으로 스레드가 반복적으로 카운트다운될 경우 대신 CyclicBarrier를 사용합니다).

반대로, 순환 장벽은 복수의 동기 포인트에 사용됩니다.예를 들어 스레드 세트가 루프/단계 계산을 실행하고 있으며 다음 반복/위상을 시작하기 전에 동기화할 필요가 있는 경우입니다.CyclicBarrier의 javadoc에 따르면:

이 장벽은 대기 스레드가 해제된 후에 재사용될 수 있기 때문에 순환이라고 불립니다.

CountDownLatch와는 달리 wait()에 대한 각 콜은 어떤 단계에 속하며 해당 단계에 속한 모든 당사자가 wait()를 호출할 때까지 스레드가 차단될 수 있습니다.CyclicBarrier에서 지원되는 명시적인 countDown() 연산은 없습니다.

이 질문은 이미 충분히 답변이 되었지만, 코드를 게재하면 조금 부가가치를 얻을 수 있을 것 같습니다.

순환 장벽의 동작을 설명하기 위해 샘플 코드를 만들었습니다.장벽이 기울어지면 자동으로 재설정되어 다시 사용할 수 있습니다(따라서 "순환").프로그램을 실행할 때, "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();
        }
    }
}

래치와 사이클릭 배리어에 대해 공부할 때 이런 은유를 생각해 냈습니다. 사이클릭 배리어:회사에 회의실이 있다고 상상해 보세요.회의를 시작하려면 일정 수의 회의 참석자가 회의에 참석해야 합니다(공식화).다음은 일반 회의 참석자(직원)의 코드입니다.

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

래치: 화가 난 상사가 고객을 위한 전시회를 개최하려면 모든 준비(자원)가 필요합니다.델은 모든 작업자(스레드)가 작업하는 작업관리 목록을 제공하고 작업관리 목록을 체크합니다(일부 작업자는 페인트 작업을 하고 다른 작업자는 사운드 시스템을 준비합니다). 작업관리 목록의 모든 항목이 완성되면(리소스가 제공됨) 고객에게 개방할 수 있습니다.

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

단, 비호환, 시간별 대기, 진단 및 위의 답변에서 자세히 설명한 모든 기능은 제외됩니다.

그러나 위의 클래스는 완전히 기능하며 제공된 기능 내에서 대응하는 이름과 동등합니다.

로 하자면, 른른 on on on on on on onCountDownLatch 클래스 AQS와 동시에 , 「」를 참조해 주세요.CyclicBarrierReentrantLock 이외의 하거나 둘 다할 수 있을 (AQS는 Lock을 합니다.)

한 가지 분명한 차이점은 N개의 CyclicBarrier에서 N개의 스레드만이 1개의 사이클로 릴리스되는 것을 대기할 수 있다는 것입니다.그러나 N의 CountDownLatch에서 대기할 수 있는 스레드 수는 무제한입니다.카운트다운 감소는 1개의 스레드 N회 또는 N개의 스레드 각각1회 또는 조합으로 실행할 수 있습니다.

CountDownLatch에서 메인 스레드는 다른 스레드의 실행이 완료될 때까지 기다립니다.CyclicBarrier에서는 워커 스레드가 서로 실행이 완료될 때까지 기다립니다.

카운트가 0에 도달하고 래치가 열리면 동일한 CountDownLatch 인스턴스를 재사용할 수 없습니다.반면 배리어 리셋으로 CyclicBarrier를 재사용할 수 있습니다.배리어 리셋은 배리어 해제 후입니다.

CyclicBarrier의 경우 모든 자 스레드가 barrier.ait() 호출을 시작하자마자 Runnable이 Barrier에서 실행됩니다.각 자 스레드의 barrier.wait는 종료까지 서로 다른 시간이 소요되며 모두 동시에 종료됩니다.

CountDownLatch는 임의의 카운트다운이며 CyclicBarrier는 스레드만의 카운트다운입니다.

작업자 스레드 5개와 발송자 스레드 1개가 있으며 작업자가 100개의 품목을 생산하면 발송자가 발송한다고 가정합니다.

CountDownLatch의 경우 카운터는 워커 또는 항목에 있을 수 있습니다.

CyclicBarrier의 경우 카운터는 워커에 대해서만 사용할 수 있습니다.

아이템의 CountDownLatch를 사용하여 작업자가 무한 sleep 상태가 되면 발송인은 발송할 수 있지만 CyclicBarrier를 사용하면 발송인을 호출할 수 없습니다.

@Kevin Lee와 @John I은 옵션 실행 가능으로 CyclicBarrier를 시도했습니다.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.

언급URL : https://stackoverflow.com/questions/4168772/java-concurrency-countdown-latch-vs-cyclic-barrier

반응형