[μ΄νŽ™ν‹°λΈŒ μžλ°”] Item17 μ™„λ²½κ³΅λž΅. CountDownLatch

2023. 2. 28. 15:36ㆍJAVA/Effective JAVA

728x90
item17. λ³€κ²½ κ°€λŠ₯성을 μ΅œμ†Œν™” ν•˜λΌ. 

" p.113 java.util.concurrent νŒ¨ν‚€μ§€μ˜ CountDownLatch ν΄λž˜μŠ€κ°€ μ΄μƒμ˜ 원칙을 잘 λ°©μ¦ν•œλ‹€."

 

 

 

java.util.concurrent νŒ¨ν‚€μ§€

: 병행(Concurrency) ν”„λ‘œκ·Έλž˜λ°μ— μœ μš©ν•˜κ²Œ μ‚¬μš©ν•  수 μžˆλŠ” μœ ν‹Έλ¦¬ν‹° 묢음 

 

- 병행(Concurrency)와 병렬(Parallelism)의 차이 

병행은 μ—¬λŸ¬ μž‘μ—…μ„ λ²ˆκ°ˆμ•„ κ°€λ©° μ‹€ν–‰ν•΄ 마치 λ™μ‹œμ— μ—¬λŸ¬ μž‘μ—…μ„ λ™μ‹œμ— μ²˜λ¦¬ν•˜λ“― λ³΄μ΄μ§€λ§Œ, μ‹€μ œλ‘œλŠ” ν•œ λ²ˆμ— 였직 ν•œ μž‘μ—…λ§Œμ„ μ‹€ν–‰ν•œλ‹€. (cpuκ°€ ν•œκ°œμ—¬λ„ κ°€λŠ₯) 

병렬은 μ—¬λŸ¬ μž‘μ—…μ„ μ‹€μ œλ‘œ λ™μ‹œμ— μ²˜λ¦¬ν•˜λŠ” κ²ƒμœΌλ‘œ cpuκ°€ μ—¬λŸ¬κ°œ μžˆμ–΄μ•Ό κ°€λŠ₯ν•˜λ‹€. 

 

μžλ°”μ˜ concurrent νŒ¨ν‚€μ§€μ—μ„œλŠ” 병행 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ— μœ μš©ν•œ λ‹€μ–‘ν•œ νˆ΄μ„ μ œκ³΅ν•œλ‹€. 

-> BlockingQueue, Callable, ConcurrentMap, Executor, ExecutorService, Future. ... 

 

 

 

CountDownLatch

: λ‹€λ₯Έ μ—¬λŸ¬ μŠ€λ ˆλ“œλ‘œ μ‹€ν–‰ν•˜λŠ” μ—¬λŸ¬ μ˜€νΌλ ˆμ΄μ…˜μ΄ 마칠 λ•ŒκΉŒμ§€ 기닀릴 λ•Œ μ‚¬μš©ν•  수 μžˆλŠ” μœ ν‹Έλ¦¬ν‹°

CountDownLatchλŠ” μŠ€λ ˆλ“œ n개λ₯Ό μ‹€ν–‰ν•˜κ³  일정 개수의 μŠ€λ ˆλ“œκ°€ λͺ¨λ‘ 끝날 λ•Œ κΉŒμ§€ κΈ°λ‹€λ €μ•Όλ§Œ λ‹€μŒμœΌλ‘œ 진행할 μˆ˜μžˆκ±°λ‚˜ λ‹€λ₯Έ μŠ€λ ˆλ“€λ₯Ό μ‹€ν–‰μ‹œν‚¬ 수 μžˆλŠ” κ²½μš°μ— μ‚¬μš©ν•œλ‹€. 

 

public class ConcurrentExample
{
   public static void main(String[] args) throws InterruptedException
   {
      int N = 10;
      CountDownLatch startSignal = new CountDownLatch(1);
      CountDownLatch doneSignal = new CountDownLatch(N);
      
      for (int i = 0; i< N; i++) // create and start threads
      {
         new Thread(new Worker(startSignal, doneSignal)).start();
      }
      
      ready(); // don't let run yet
      startSignal.countDown(); // let all threads proceed
      doneSignal.await(); // wait for all to finish
      done();
      
   }
   
   private static void ready()
   {
      System.out.println("ready~~~");
   }
   
   private static void done()
   {
      System.out.println("done~~~");
   }
   
   private static class Worker implements Runnable
   {
      private final CountDownLatch startSignal;
      private final CountDownLatch doneSignal;
      
      public Worker(CountDownLatch startSignal, CountDownLatch doneSignal)
      {
         this.startSignal = startSignal;
         this.doneSignal = doneSignal;
      }
      
      @Override
      public void run()
      {
         try
         {
            doWork();
            doneSignal.countDown();
            startSignal.await();
         }
         catch (InterruptedException e) {
         
         }
      }
      
       void doWork()
      {
         System.out.println("working thread : " + Thread.currentThread().getName());
      }
   }
}

CountDownLatchλŠ” μ΄ˆκΈ°ν™”ν•  λ•Œ μ •μˆ˜κ°’ countλ₯Ό λ„£μ–΄μ£Όκ³  μŠ€λ ˆλ“œλŠ” λ§ˆμ§€λ§‰μ— countDown() λ©”μ…”λ“œλ₯Ό λΆˆλŸ¬μ€€λ‹€. 

그러면 μ΄ˆκΈ°ν™”ν•  λ•Œ λ„£μ–΄μ€€ μ •μˆ˜κ°’μ΄ ν•˜λ‚˜ λ‚΄λ €κ°€κ³ , 각 μŠ€λ ˆλ“œλŠ” λ§ˆμ§€λ§‰μ— μžμ‹ μ΄ μ‹€ν–‰μ™„λ£Œν–ˆμŒμ„ countDown λ©”μ„œλ“œλ‘œ μ•Œλ €μ€€λ‹€. 

그리고 이 μŠ€λ ˆλ“œλ“€μ΄ λλ‚˜κΈ°λ₯Ό κΈ°λ‹€λ¦¬λŠ” μͺ½ μž…μž₯μ—μ„œλŠ” await() λ©”μ„œλ“œλ₯Ό λΆˆλŸ¬μ€€λ‹€. 그러면 ν˜„μž¬ λ©”μ„œλ“œκ°€ 싀행쀑인 λ©”μΈμŠ€λ ˆλ“œλŠ” 더이상 μ§„ν–‰ν•˜μ§€ μ•Šκ³  countDownLatch의 countκ°€ 0이 될 λ•ŒκΉŒμ§€ κΈ°λ‹€λ¦°λ‹€. 

 

 

int N = 10;
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(N);

-> μ΄ˆκΈ°ν™” ν•  λ•Œ 숫자λ₯Ό μž…λ ₯ν•˜κ³ ,

startSignal.countDown(); // let all threads proceed
doneSignal.await(); // wait for all to finish

await() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•΄μ„œ μˆ«μžκ°€ 0이 될 λ•ŒκΉŒμ§€ κΈ°λ‹€λ¦°λ‹€. 그리고 숫자λ₯Ό μ…€ λ•ŒλŠ” countDown() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•œλ‹€. 

 

 

countDownLatchλŠ” μ‹œμž‘ λ˜λŠ” μ’…λ£Œ μ‹ ν˜Έλ‘œ μ‚¬μš©ν•  수 있으며, μž¬μ‚¬μš©ν•  수 μžˆλŠ” μΈμŠ€ν„΄μŠ€κ°€ μ•„λ‹ˆκΈ° λ•Œλ¬Έμ— 숫자λ₯Ό λ¦¬μ…‹ν•΄μ„œ μž¬μ‚¬μš©ν•˜λ €λ©΄ CyclicBarrierλ₯Ό μ‚¬μš©ν•΄μ•Ό ν•œλ‹€. 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90