본문 바로가기
Language/Java

[JAVA] 자바 동기화의 정수 : CountDownLatch vs CyclicBarrier 완벽 비교 가이드

by Papa Martino V 2026. 1. 22.
728x90

CountDownLatch vs CyclicBarrier
CountDownLatch vs CyclicBarrier

 

자바 멀티스레드 프로그래밍에서 여러 스레드의 작업 완료 시점을 맞추거나 특정 지점에서 스레드들을 대기시키는 것은 매우 까다로운 작업입니다. 자바의 java.util.concurrent 패키지는 이를 위해 CountDownLatchCyclicBarrier라는 두 가지 강력한 동기화 도구를 제공합니다. 비슷해 보이지만 그 목적과 작동 방식은 판이하게 다릅니다. 본 글에서는 실무에서 이들을 어떻게 선택하고 활용해야 하는지 전문적으로 분석해 보겠습니다.


1. CountDownLatch: "결승선에서 기다리는 심판"

CountDownLatch는 하나 이상의 스레드가 다른 스레드들의 일련의 작업이 완료될 때까지 기다리도록 하는 동기화 도구입니다. 카운트다운(Count Down)이라는 이름처럼 설정된 숫자가 0이 될 때까지 대기 중인 스레드를 붙잡아 둡니다.

  • 동작 원리: 생성자에서 설정한 숫자를 countDown() 메서드가 호출될 때마다 1씩 감소시키며, 0이 되는 순간 await()를 호출하여 대기하던 스레드들이 해제됩니다.
  • 특징: 일회용입니다. 한 번 0이 되면 다시 사용할 수 없습니다.

2. CyclicBarrier: "모두 모여야 출발하는 투어 가이드"

CyclicBarrier는 여러 스레드가 서로를 특정 지점(Barrier)에서 기다리게 하여, 모든 스레드가 그 지점에 도착했을 때 다음 단계를 진행하도록 합니다.

  • 동작 원리: 모든 스레드가 await()를 호출하여 정해진 숫자의 스레드가 모이면 장벽이 무너지고 다음 로직이 실행됩니다.
  • 특징: 이름에 'Cyclic'이 들어간 것처럼, 장벽이 무너진 후 reset()을 통해 재사용이 가능합니다.

3. CountDownLatch vs CyclicBarrier 핵심 비교

두 도구의 결정적인 차이점을 한눈에 파악할 수 있도록 표로 정리했습니다.

비교 항목 CountDownLatch CyclicBarrier
주요 목적 다른 스레드의 작업 완료를 기다림 스레드 간의 상호 대기 및 동기화
재사용성 재사용 불가 (일회용) 재사용 가능 (Cyclic)
대기 스레드 주로 메인 스레드나 관리 스레드가 대기 작업을 수행하는 모든 스레드가 대기
핵심 메서드 countDown(), await() await()
Barrier Action 지원하지 않음 모든 스레드 도착 시 별도 로직 실행 가능

4. 실무 코드 샘플: 언제 무엇을 써야 할까?

사례 A: 서비스 시작 전 필수 리소스 초기화 (CountDownLatch)

여러 개의 초기화 모듈이 완료되어야 메인 서버가 구동되는 시나리오에 적합합니다.


CountDownLatch latch = new CountDownLatch(3);

// 3개의 모듈이 각각 완료 시 latch.countDown() 호출
// 메인 스레드
latch.await(); // 3개가 모두 끝나야 통과
System.out.println("모든 리소스 초기화 완료. 서버 구동!");
    

사례 B: 병렬 데이터 처리 후 단계별 합산 (CyclicBarrier)

각 스레드가 각자의 파트를 계산하고, 모두 모여 합계 결과를 낸 뒤 다음 단계로 넘어가는 반복 작업에 적합합니다.


CyclicBarrier barrier = new CyclicBarrier(4, () -> {
    System.out.println("모든 스레드 도착! 합산 로직 실행");
});

// 4개의 스레드가 각각 연산 수행 후
barrier.await(); // 4명이 다 모여야 다음 코드로 진행
    

5. 전문 개발자를 위한 최적화 팁

  1. 타임아웃 활용: await(long timeout, TimeUnit unit)을 사용하여 특정 스레드의 문제로 인해 시스템 전체가 영원히 대기 상태(Deadlock)에 빠지는 것을 방지하십시오.
  2. 예외 처리: CyclicBarrier는 한 스레드라도 중단되면 BrokenBarrierException을 발생시킵니다. 트랜잭션의 원자성을 위해 적절한 복구 로직이 필요합니다.
  3. 메모리 가시성: 두 도구 모두 내부적으로 volatile 필드와 CAS 연산을 활용하여 스레드 간의 메모리 가시성을 보장합니다.

6. 결론: 선택의 기준

CountDownLatch는 '어떤 사건'들이 일어나는지를 체크할 때 유용하며, CyclicBarrier는 '참여자'들이 서로를 기다려야 할 때 유용합니다. 재사용이 필요한가? 참여 스레드가 모두 대기해야 하는가? 이 두 가지 질문만으로도 여러분은 상황에 맞는 최적의 동기화 도구를 선택할 수 있습니다.

 

내용 출처 및 참고 문헌:

  • Java Platform, Standard Edition 17 API Specification
  • Java Concurrency in Practice (Brian Goetz)
  • Baeldung: CountDownLatch vs CyclicBarrier in Java
728x90