티스토리 뷰

CountDownLatch는 하나 이상의 스레드가 다른 스레드들의 작업 완료를 기다릴 수 있게 해주는 일회성 동기화 도구(synchronization aid) 이다. "일회성"이라고 표현한 이유는 한 번 사용하면 재사용 할 수 없다는 뜻이다. 동시성 테스트에서는 스레드들의 동시 시작을 조율 하는 용도로 활용된다.

핵심 동작 원리

생성 시 카운트 값을 지정하고, countDown() 호출 시 카운트를 1씩 감소시킨다. await()을 호출한 스레드는 카운트가 0이 될 때까지 블로킹된다. 카운트가 0이 되는 순간 await()에서 대기하던 모든 스레드가 실행을 재개한다.

  • 카운트가 0에 도달하면 리셋할 수 없다.
  • 카운트가 이미 0인 상태에서 countDown()을 호출하면 아무 일도 일어나지 않는다.
  • 카운트가 이미 0인 상태에서 await()을 호출하면 블로킹 없이 즉시 통과한다.

주요 메서드

메서드 설명
countDown() 카운트를 1 감소. 0이 되면 대기 중인 스레드들이 깨어남
await() 카운트가 0이 될 때까지 블로킹
await(long timeout, TimeUnit unit) 타임아웃 지정. 시간 내 0이 되면 true, 초과하면 false 반환. 무한 대기 방지용으로 실무에서 권장
getCount() 현재 남은 카운트 반환. 디버깅/로깅 용도. TOCTOU 문제로 분기 로직에 사용하면 안 됨

동시 시작 조율 패턴

동시성 테스트에서 여러 스레드의 동시 시작을 조율하는 패턴이다.

int threadCount = 200;
CountDownLatch startSignal = new CountDownLatch(1);        // 동시 시작용
CountDownLatch doneSignal = new CountDownLatch(threadCount); // 완료 대기용
ExecutorService executor = Executors.newFixedThreadPool(threadCount);

for (int i = 0; i < threadCount; i++) {
    executor.submit(() -> {
        try {
            startSignal.await();   // 모든 스레드가 여기서 대기 동시 실행 보장
            doWork();
        } finally {
            doneSignal.countDown(); // 작업 완료 알림
        }
    });
}

startSignal.countDown();  // 카운트 1→0, 모든 스레드 동시 출발
doneSignal.await();        // 모든 작업 완료 대기
executor.shutdown();

흐름 정리:

  1. executor.submit()은 태스크를 스레드 풀의 작업 큐에 넣고 즉시 반환
  2. 각 워커 스레드가 태스크를 꺼내 실행하면서 startSignal.await()에서 블로킹
  3. for 루프 완료 후 메인 스레드가 startSignal.countDown() 호출 → 카운트 0 → 전체 스레드 동시 출발
  4. 각 스레드 완료 시 doneSignal.countDown() 호출
  5. 메인 스레드는 doneSignal.await()에서 전체 완료 대기

동시 시작이 완벽하게 보장되지 않을 수 있다.
모든 스레드가 startSignal.await()에 도달하기 전에 startSignal.countDown()이 호출될 수 있다. 이 경우 뒤늦게 await()을 호출한 스레드는 블로킹 없이 즉시 통과하므로, 먼저 도착한 스레드와 시작 시점 차이가 발생한다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2026/05   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
글 보관함