[JAVA:병렬 프로그래밍 - 2] CyclicBarrier 사용하기.
CyclicBarrier 를 사용하면 동시에 실행되는 쓰레드 내부 원하는 지점에서 대기를 걸어주고 모든 쓰레드가 대기 상태에 들어갔을때, 대기를 풀어주는 동작을 할 수 있다.
예를들어 설명하면 N 개의 쓰레드가 돌고 있다고 가정하고 CyclicBarrier 를 생성할 때 인자값으로 N 을 준다. 각각의 쓰레드 내에서 CyclicBarrier 의 await() 를 호출하고 호출 횟수가 N번에 도달했을 때, N개의 모든 쓰레드의 대기 상태가 해제된다.
아래 그림 참고. 설명이 조금 애매한데, 그냥 대충 보고 눈치것 이해하는 것이 좋다.
CyclicBarrier를 활용한 예제코드:
public class main { private final static int THREADS = 5; private static CyclicBarrier cyclicBarrier = new CyclicBarrier(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); System.out.println("Thread(" + id + ") : End Sleep"); } catch (InterruptedException e) { e.printStackTrace(); } try { // 대기. cyclicBarrier 를 생성할 때, 인자값으로 준 count 개수만큼 // await를 호출한다면 모든 쓰레드의 wait 상태가 종료된다. cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } System.out.println("Thread(" + id + ") : End."); } } public static void main(String[] args) { // 쓰레드를 10개 생성. for(int i = 0; i < THREADS; ++i) { new Thread(new RandomSleepRunnable(i)).start(); } } }
결과:
Thread(0) : Start. Thread(2) : Start. Thread(2) : Sleep 1128ms Thread(0) : Sleep 1205ms Thread(1) : Start. Thread(1) : Sleep 1968ms Thread(4) : Start. Thread(3) : Start. Thread(4) : Sleep 1834ms Thread(3) : Sleep 1020ms Thread(3) : End Sleep Thread(2) : End Sleep Thread(0) : End Sleep Thread(4) : End Sleep Thread(1) : End Sleep Thread(1) : End. Thread(3) : End. Thread(4) : End. Thread(0) : End. Thread(2) : End.