[java] CountDownLatch 대 세마포

사용의 이점이 있습니까?

java.util.concurrent.CountdownLatch

대신에

java.util.concurrent.Semaphore ?

내가 말할 수있는 한 다음 조각은 거의 동일합니다.

1. 세마포어

final Semaphore sem = new Semaphore(0);
for (int i = 0; i < num_threads; ++ i)
{
  Thread t = new Thread() {
    public void run()
    {
      try
      {
        doStuff();
      }
      finally
      {
        sem.release();
      }
    }
  };
  t.start();
}

sem.acquire(num_threads);

2 : CountDownLatch

final CountDownLatch latch = new CountDownLatch(num_threads);
for (int i = 0; i < num_threads; ++ i)
{
  Thread t = new Thread() {
    public void run()
    {
      try
      {
        doStuff();
      }
      finally
      {
        latch.countDown();
      }
    }
  };
  t.start();
}

latch.await();

2 번 경우를 제외하고는 래치를 재사용 할 수 없으며 더 중요한 것은 생성 될 스레드 수를 미리 알아야합니다 (또는 래치를 생성하기 전에 모두 시작될 때까지 기다려야 함).

그렇다면 어떤 상황에서 래치가 더 좋을까요?



답변

CountDown 래치는 예제와 정반대로 자주 사용됩니다. 일반적으로 countown이 0에 도달하면 동시에 시작되는 “await ()”에서 많은 스레드를 차단합니다.

final CountDownLatch countdown = new CountDownLatch(1);
for (int i = 0; i < 10; ++ i){
   Thread racecar = new Thread() {
      public void run()    {
         countdown.await(); //all threads waiting
         System.out.println("Vroom!");
      }
   };
   racecar.start();
}
System.out.println("Go");
countdown.countDown();   //all threads start now!

이를 MPI 스타일의 “장벽”으로 사용하여 모든 스레드가 진행하기 전에 다른 스레드가 특정 지점을 따라 잡을 때까지 기다리게 할 수도 있습니다.

final CountDownLatch countdown = new CountDownLatch(num_thread);
for (int i = 0; i < num_thread; ++ i){
   Thread t= new Thread() {
      public void run()    {
         doSomething();
         countdown.countDown();
         System.out.printf("Waiting on %d other threads.",countdown.getCount());
         countdown.await();     //waits until everyone reaches this point
         finish();
      }
   };
   t.start();
}

즉, CountDown 래치는 예제에서 보여준 방식으로 안전하게 사용할 수 있습니다.


답변

CountDownLatch 는 일련의 스레드를 시작한 다음 모든 스레드가 완료 될 때까지 (또는 countDown()지정된 횟수만큼 호출 될 때까지 대기하는 데 사용됩니다 .

세마포는 리소스를 사용하는 동시 스레드 수를 제어하는 ​​데 사용됩니다. 해당 리소스는 파일과 같은 것이거나 실행중인 스레드 수를 제한하여 CPU가 될 수 있습니다. 세마포어의 카운트는 다른 스레드가 acquire()release().

귀하의 예에서는 본질적으로 Semaphore를 일종의 Count UP Latch로 사용하고 있습니다. 당신의 의도가 모든 스레드가 끝날 때까지 기다리는 것이므로를 사용하면 CountdownLatch의도가 더 명확 해집니다.


답변

짧은 요약:

  1. SemaphoreCountDownLatch 는 다른 용도로 사용됩니다.

  2. Semaphore 를 사용 하여 리소스에 대한 스레드 액세스를 제어합니다.

  3. CountDownLatch 를 사용 하여 모든 스레드가 완료 될 때까지 기다립니다.

javadocs의 세마포어 정의 :

세마포는 허가 세트를 유지한다. 각 acquire ()허가 를 사용할 수 있을 때까지 필요한 경우 차단 한 다음 가져옵니다. 각 release () 는 허가를 추가하여 잠재적으로 차단 취득자를 해제합니다.

그러나 실제 허용 개체는 사용되지 않습니다. 세마포어는 바로 사용할 수있는 수의 수를 유지하고 그에 따라 역할을합니다.

어떻게 작동합니까?

세마포는 리소스를 사용하는 동시 스레드 수를 제어하는 ​​데 사용됩니다. 해당 리소스는 공유 데이터, 코드 블록 ( 중요 섹션 ) 또는 파일 과 같은 것일 수 있습니다 .

세마포어의 카운트는 다른 스레드가 acquire() 및 release()를 호출함에 따라 증가 및 감소 할 수 있습니다 . 그러나 어느 시점에서든 세마포어 수보다 많은 수의 스레드를 가질 수 없습니다.

세마포 사용 사례 :

  1. 디스크에 대한 동시 액세스 제한 (경쟁하는 디스크 탐색으로 인해 성능이 저하 될 수 있음)
  2. 스레드 생성 제한
  3. JDBC 연결 풀링 / 제한
  4. 네트워크 연결 조절
  5. CPU 또는 메모리 집약적 인 작업 제한

세마포어 사용에 대한 이 기사 를 살펴보십시오 .

javadocs의 CountDownLatch 정의 :

다른 스레드에서 수행중인 작업 집합이 완료 될 때까지 하나 이상의 스레드가 대기 할 수 있도록하는 동기화 지원입니다.

어떻게 작동합니까?

CountDownLatch 는 스레드가 실행을 완료 할 때마다 감소하는 스레드 수로 카운터를 초기화하여 작동합니다. count가 0에 도달하면 모든 스레드가 실행을 완료하고 래치에서 대기중인 스레드가 실행을 다시 시작 함을 의미합니다.

CountDownLatch 사용 사례 :

  1. 최대 병렬 처리 달성 : 때로는 최대 병렬 처리를 달성하기 위해 동시에 여러 스레드를 시작하려고합니다.
  2. 실행을 시작하기 전에 N 스레드가 완료 될 때까지 기다립니다.
  3. 교착 상태 감지.

CountDownLatch 개념을 명확하게 이해하려면 이 기사 를 살펴보십시오 .

기사 에서도 Fork Join Pool 을 살펴보십시오 . CountDownLatch 와 몇 가지 유사점이 있습니다.


답변

포섬을 찾고 싶어 골프 프로 샵에 들어갔다고 가정 해 보겠습니다.

프로 샵 직원 중 한 명으로부터 티타임을 받기 위해 줄을 서면 기본적으로에게 전화 proshopVendorSemaphore.acquire()를했고, 티타임을 proshopVendorSemaphore.release()받으면 에게 전화를 걸었습니다. 참고 : 무료 직원이 서비스를 제공 할 수 있습니다.

이제 시작으로 걸어 가면 그는 a를 시작하고 다른 사람을 기다리 CountDownLatch(4)라고 전화 await()합니다 CountDownLatch. countDown()나머지 포섬도 마찬가지입니다. 모두 도착하면 스타터는 계속 진행합니다 ( await()콜 리턴)

이제 9 홀 후에 각자 휴식을 취하면 가상적으로 스타터를 다시 투입 할 수 있습니다. 그는 ‘new’ CountDownLatch(4)를 사용하여 홀 10을 티 오프합니다. 홀 1과 동일한 대기 / 동기화입니다.

그러나 스타터가 a CyclicBarrier를 사용 하여 시작했다면 & throw를 사용하는 두 번째 래치 대신 홀 10에서 동일한 인스턴스를 재설정 할 수 있습니다.


답변

자유롭게 사용할 수있는 소스를 살펴보면 두 클래스의 구현에 마법이 없으므로 성능이 거의 동일해야합니다. 당신의 의도를 더 분명하게 만드는 것을 선택하십시오.


답변

CountdownLatchawait()카운트가 0에 도달 할 때까지 스레드가 메서드에서 대기하도록합니다 . 따라서 모든 스레드가 무언가를 3 번 ​​호출 할 때까지 기다리면 모든 스레드가 진행될 수 있습니다. A는 Latch일반적으로 재설정 할 수 없습니다.

A Semaphore는 스레드가 허가를 검색 할 수 있도록하여 너무 많은 스레드가 한 번에 실행되는 것을 방지하고 진행에 필요한 허가를 얻을 수없는 경우 차단합니다. Semaphore다른 대기 스레드가 진행할 수 있도록 허용을로 반환 할 수 있습니다 .


답변