Java

[Java] CountDownLatch 사용

dobidugi 2024. 5. 2. 10:13

자바는 멀티 쓰레드 프로그래밍이 가능한 언어이다. 

만약 멀티 쓰레드 작업을 해야하는 상황이 있다면 자바의 CountDownLatch를 함께 활용하면 좋다.

CountDownLatch

CountDownLatch는 하나 이상의 스레드가 다른 스레드에서 수행중인 작업이 완료될 떄 까지 기다릴 수 있도록 해주는 클래스다.

 

예를 들어 어떠한 스레드에서 5개의 스레드를 생성하고 해당 스레드가 완료 된 후에 어떠한 작업을 처리해야하는 상황이 있다면 CountDownLatch를 활용하여 쉽게 구현할 수 있다.

사용법

생성

    final int JOB_COUNT = 5;
    CountDownLatch latch = new CountDownLatch(JOB_COUNT);

CountDownLatch 생성할때 작업할 스레드 갯수를 넘겨준다.

countDown()

for(int i=0; i<JOB_COUNT; i++) {
    final int SEQ = i;
    executorService.submit(() -> {
      try {
        System.out.println(SEQ + " 번째 JOB " );
      } finally {
        latch.countDown();
      }
    });
}

스레드 작업이 끝나면 countDown 메서드를 호출하여 카운트를 감소 시킨다.

await()

latch.await();

await 메서드는 CountDownLatch의 count가 0이 될떄까지 다음 작업을 수행하지않고 기다린다.

package org.example;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {
  public static void main(String[] args) throws InterruptedException {
    final int JOB_COUNT = 5;
    CountDownLatch latch = new CountDownLatch(JOB_COUNT);
    ExecutorService executorService = Executors.newFixedThreadPool(JOB_COUNT);
    System.out.println("START");
    for(int i=0; i<JOB_COUNT; i++) {
        final int SEQ = i;
        executorService.submit(() -> {
          try {
            System.out.println(SEQ + " 번째 JOB " );
          } finally {
            latch.countDown();
          }
        });
    }
    latch.await();
    System.out.println("END");
  }
}
// START
// 4 번째 
// 1 번째 
// 0 번째 
// 3 번째 
// 2 번째 
// END

await(long timeout, TimeUnit unit)

만약 스레드가 도중에 죽어 countdown() 메서드를 호출하지 못할경우나 특정한 작업들이 특정한 시간을 넘겨서는 안되는 경우에도 편리하게 이용할 수 있다. 

latch.await(100, TimeUnit.MILLISECONDS);

이 경우에는 100ms 이후에  count값이 0이 아니라도 다음 작업을 수행 시킨다.

package org.example;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class Main {
  public static void main(String[] args) throws InterruptedException {
    final int JOB_COUNT = 5;
    CountDownLatch latch = new CountDownLatch(JOB_COUNT);
    ExecutorService executorService = Executors.newFixedThreadPool(JOB_COUNT);
    System.out.println("START");
    for(int i=0; i<JOB_COUNT; i++) {
        final int SEQ = i;
        executorService.submit(() -> {
          try {
            Thread.sleep(500);
            System.out.println(SEQ + " 번째 JOB " );
          } catch (InterruptedException e) {
            throw new RuntimeException(e);
          } finally {
            latch.countDown();
          }
        });
    }
    latch.await(100, TimeUnit.MILLISECONDS);
    System.out.println("END");
  }
}
// START
// END
// 4 번째 
// 1 번째 
// 0 번째 
// 3 번째 
// 2 번째

참고

https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/CountDownLatch.html

https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/TimeUnit.html