[JAVA:병렬 프로그래밍 - 1] CountDownLatch 사용하기.
만약 백그라운드에서 실행되고 있는 싱글 쓰레드가 종료되기를 기다리는 코드를 작성해야 한다면 당장 Thread 클래스의 join() 메소드 부터 떠올리게 될 것이다. 아래와 같이 말이다.
간단한 join() 사용예:
Thread thread = new Thread() { @Override public void run() { System.out.println("start trhead."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("end trhead."); } }; thread.start(); try { // 스레드가 끝날때 까지 대기한다. thread.join(); } catch (InterruptedException e) { e.printStackTrace(); }System.out.println("Thread terminated.");
하지만, 멀티 쓰레드에서 모든 동작이 끝나기를 기다려야 하는 상황이라면 join 을 사용하기 조금 난감하다. 이럴 땐 CountDownLatch 를 사용하면 참 편리하다. (안드로이드 API 설명 페이지로 링크합니다. 이 곳이 오라클 페이지보다 보기 좋아서;; http://developer.android.com/reference/java/util/concurrent/CountDownLatch.html )
CountDownLatch 는 생성할 때 1 이상의 카운트를 인자값으로 받는다. 그리고 특정 메소드 내부에서 await() 메소드로 대기 상태를 만들어주고 CountDownLatch 를 생성할 때 설정한 count 가 0이 되기만들 기다렸다가 0이 되는 순간 대기 상태를 해제한다. 원리는 아래 그림과 같다.
예제코드를 살펴보면 아래와 같다.
CountDownLatch 를 활용한 예제코드:
public class main { private final static int THREADS = 10; private static CountDownLatch lacth = new CountDownLatch(THREADS); public static class RandomSleepRunnable implements Runnable { private int id = 0; private static Random random = new Random(System.currentTimeMillis()); public RandomSleepRunnable(int id) { this.id = id; } @Override public void run() { System.out.println("Thread(" + id + ") : Start."); // 1000ms 에서 2000ms 사이의 딜레이 값을 랜덤하게 생성. int delay = random.nextInt(1001) + 1000; try { System.out.println("Thread(" + id + ") : Sleep " + delay + "ms"); Thread.sleep(delay); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread(" + id + ") : End."); // lacth 의 카운터에서 -1. lacth.countDown(); } } public static void main(String[] args) { // 쓰레드를 10개 생성. for(int i = 0; i < THREADS; ++i) { new Thread(new RandomSleepRunnable(i)).start(); } try { // lacth 의 카운트가 0이 될 때 까지 대기한다. lacth.await(); // 아래와 같이 TimeOut 을 설정할 수 있다. // 아래의 경우는, 만약 2000ms 동안 latch 의 카운트가 0 되지 않는다면 // wait 상태를 해제하고 다음 동작으로 넘어간다. //lacth.await(2000, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("All threads terminated."); } }
결과:
Thread(1) : Start. Thread(1) : Sleep 1267ms Thread(2) : Start. Thread(0) : Start. Thread(0) : Sleep 1168ms Thread(2) : Sleep 1085ms Thread(5) : Start. Thread(4) : Start. Thread(4) : Sleep 1573ms Thread(5) : Sleep 1868ms Thread(3) : Start. Thread(3) : Sleep 1552ms Thread(6) : Start. Thread(6) : Sleep 1869ms Thread(7) : Start. Thread(8) : Start. Thread(7) : Sleep 1001ms Thread(8) : Sleep 1636ms Thread(9) : Start. Thread(9) : Sleep 1573ms Thread(7) : End. Thread(2) : End. Thread(0) : End. Thread(1) : End. Thread(3) : End. Thread(4) : End. Thread(9) : End. Thread(8) : End. Thread(5) : End. Thread(6) : End. All threads terminated.
매우 간단하고 사용하기도 편리하다.