CountDownLatch — 카운트다운 동기화 장치
CountDownLatch — 카운트다운 동기화 장치
CountDownLatch는 다른 스레드에서 수행 중인 일련의 연산이 완료될 때까지 하나 이상의 스레드가 기다리게 하는 동기화 보조 장치예요. 특정 작업들이 모두 끝났을 때 진행을 허용하는 "게이트(gate)"로 자주 쓰여요.
본문
개념 이해하기
CountDownLatch는 주어진 카운트로 초기화돼요. await 메서드는 countDown() 호출로 현재 카운트가 0이 될 때까지 차단하며, 0이 되면 모든 대기 스레드가 해제되고 이후의 await 호출은 즉시 반환돼요.
public class CountDownLatch
extends Object
이것은 일회성(one-shot) 이에요 — 카운트는 재설정할 수 없어요. 재설정이 필요하면 CyclicBarrier를 고려하세요.
- 카운트 1: 단순한 on/off 래치 또는 게이트 역할. 모든
await호출 스레드는countDown()이 게이트를 열 때까지 기다려요. - 카운트 N: 한 스레드가 N개의 스레드가 어떤 액션을 완료하거나, 어떤 액션이 N번 완료될 때까지 기다리게 해요.
유용한 속성: countDown을 호출하는 스레드가 카운트가 0에 도달할 때까지 기다릴 필요 없고, 단지 모든 스레드가 통과할 수 있을 때까지 await를 지나 진행하지 못하게 막는다는 점이에요.
메모리 일관성 효과: 카운트가 0에 도달할 때까지, 한 스레드에서 countDown()을 호출하기 전의 동작은 다른 스레드에서 대응하는 await()의 성공적 반환에 뒤따르는 동작보다 happen-before 관계예요.
활용 예 — 시작 신호 + 완료 신호
class Driver { // ...
void main() throws InterruptedException {
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(N);
for (int i = 0; i < N; ++i) // create and start threads
new Thread(new Worker(startSignal, doneSignal)).start();
doSomethingElse(); // don't let run yet
startSignal.countDown(); // let all threads proceed
doSomethingElse();
doneSignal.await(); // wait for all to finish
}
}
class Worker implements Runnable {
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
}
public void run() {
try {
startSignal.await();
doWork();
doneSignal.countDown();
} catch (InterruptedException ex) {} // return;
}
void doWork() { ... }
}
활용 예 — 문제 분할
문제를 N개로 나누고 각 부분을 실행 후 래치를 감소시키는 Runnable로 기술해 Executor에 제출하면, 모든 부분이 완료됐을 때 조정 스레드가 await를 통과할 수 있어요.
class Driver2 { // ...
void main() throws InterruptedException {
CountDownLatch doneSignal = new CountDownLatch(N);
Executor e = ...;
for (int i = 0; i < N; ++i)
e.execute(new WorkerRunnable(doneSignal, i));
doneSignal.await(); // wait for all to finish
}
}
생성자
public CountDownLatch(int count) — 주어진 카운트로 초기화된 CountDownLatch를 만들어요.
IllegalArgumentException—count가 음수일 때
메서드
public void await() throws InterruptedException — 래치가 0까지 감소될 때까지 현재 스레드를 기다리게 해요. 현재 카운트가 0이면 즉시 반환. 카운트가 0보다 크면 countDown()으로 카운트가 0이 되거나, 다른 스레드가 현재 스레드를 인터럽트할 때까지 대기 상태가 돼요.
InterruptedException— 대기 중 인터럽트(인터럽트 상태는 클리어됨)
public boolean await(long timeout, TimeUnit unit) throws InterruptedException — 래치가 0까지 감소되거나, 인터럽트되거나, 지정 대기 시간이 지날 때까지 기다려요. 카운트가 0이 되면 true, 시간이 지나면 false. 시간이 0보다 작거나 같으면 전혀 기다리지 않아요.
InterruptedException
public void countDown() — 래치의 카운트를 감소시켜요. 카운트가 0에 도달하면 모든 대기 스레드를 해제해요. 현재 카운트가 0이면 아무 일도 일어나지 않아요.
public long getCount() — 현재 카운트를 반환해요. 주로 디버깅·테스트용.
public String toString() — 이 래치와 상태 "Count =" + 현재 카운트를 식별하는 문자열을 반환해요.