개요
사실 오래 전에 배워서 사용했던 Phaser라는 기능이 가물가물해서 기억을 하고자 CountDownLatch와 CyclicBarrier를 비교하면서 복습을 해보았다.
하지만 대부분 Phaser보다는 CountDownLath,CyclicBarrier를 많이 사용하지 않을까 싶다.
CountDownLatch
일단 Latch(빗장이었나?)로 걸어잠그고 숫자를 다 세면 열어주는 것이다. 그래서 만약에 CountDownLatch에 카운트를 5로 지정하면 0이 될때까지 현재 스레드가 기다린다.CyclicBarrier
CyclicBarrier는 스레드 그룹이 모두 wait하고 있는 지점에 도달 할 때까지 기다린다.이 시점에서 Barrier가 깨지면서 일을 할 수 있게 된다. 뭐 일을 안해도 되고 해도 된다.
차이점
Task vs Treads
보면 알겠지만 CountDownLatch는 숫자를 세는데 중점을 두고, CyclicBarrier는 모두 다 오길 기다린다.CountDownLatch는 동일한 녀석이 숫자를 두번 세도 상관이 없다.
CyclicBarrier는 한명당 하나의 카운트라고 생각하면 된다. 무조건 다와야 한다.
CountDownLatch countDownLatch = new CountDownLatch(2); Thread t = new Thread(() -> { countDownLatch.countDown(); countDownLatch.countDown(); }); t.start(); countDownLatch.await(); System.out.println("code1"); System.out.println(0 == countDownLatch.getCount()); System.out.println("===");
CyclicBarrier cyclicBarrier = new CyclicBarrier(2); Thread t = new Thread(() -> { try { cyclicBarrier.await(); cyclicBarrier.await(); catch (InterruptedException | BrokenBarrierException e) { e.printStackTrace(); } }); t.start(); System.out.println("code2"); System.out.println(1 == cyclicBarrier.getNumberWaiting()); System.out.println(cyclicBarrier.isBroken()); System.out.println("===");
재사용성
CyclicBarrier는 wait()에 도달해서 다음으로 넘어가면 count값이 원래 값으로 바뀐다. 무한이 돈다CountDownLatch에서는 한번 도달하면 끝이다.
ListoutputScraper = Collections.synchronizedList(new ArrayList<>()); CountDownLatch countDownLatch = new CountDownLatch(7); ExecutorService es = Executors.newFixedThreadPool(20); for (int i = 0; i < 20; i++) { es.execute(() -> { long prevValue = countDownLatch.getCount(); countDownLatch.countDown(); if (countDownLatch.getCount() != prevValue) { outputScraper.add("Count Updated"); } }); } es.shutdown(); System.out.println(outputScraper); System.out.println(outputScraper.size() <= 7);
// https://docs.oracle.com/javase/6/docs/api/java/util/concurrent/package-summary.html // https://stackoverflow.com/questions/6916385/is-there-a-concurrent-list-in-javas-jdk 참고 // Collections.synchronizedList는 내가 임의로 넣은 것이다. List다음에는 Phaser에 대해 알아보자.outputScraper = Collections.synchronizedList(new ArrayList<>()); CyclicBarrier cyclicBarrier = new CyclicBarrier(7); ExecutorService es = Executors.newFixedThreadPool(20); for (int i = 0; i < 20; i++) { es.execute(() -> { int numberWaiting = cyclicBarrier.getNumberWaiting(); if (numberWaiting >= 0) { outputScraper.add("Count Updated"); } try { cyclicBarrier.await(); } catch (InterruptedException | BrokenBarrierException e) { e.printStackTrace(); } }); } es.shutdown(); System.out.println(outputScraper); System.out.println(outputScraper.size() > 7); cyclicBarrier.await();