자바는 멀티 쓰레드 프로그래밍이 가능한 언어이다.
만약 멀티 쓰레드 작업을 해야하는 상황이 있다면 자바의 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/TimeUnit.html