CountDownLatchとセマフォ


92

使用する利点はありますか

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の場合を除いて、ラッチは再利用できません。さらに重要なことには、作成されるスレッドの数を事前に知る必要があります(または、すべてのスレッドが開始されるまで待ってからラッチを作成します)。

それでは、どのような状況でラッチが望ましいのでしょうか?

回答:


109

CountDownラッチは、例の正反対の場合によく使用されます。一般に、countownがゼロに達したときにすべて同時に開始される「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ラッチは、例で示した方法で安全に使用できます。


1
ありがとう。したがって、sem.acquire(num_threads);でない限り、複数のスレッドがラッチで待機できる場合、私の2つの例は同等ではありません。sem.release(num_threads);が後に続きますか?私はそれらが再び同等になると思います。
finnw 2008年

ある意味では、そうです、すべてのスレッドがacquireに続いてreleaseを呼び出す限り。厳密に言えば、いいえ。ラッチを使用すると、すべてのスレッドを同時に開始できます。セマフォを使用すると、それらは次々に適格になります(その結果、スレッドのスケジューリングが異なる可能性があります)。
James Schek、2008年

Javaのドキュメントは、これがCountdownLatchが彼の例docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/…にうまく適合することを暗示しているようです。具体的には、「Nに初期化されたCountDownLatchを使用して、Nスレッドが何らかのアクションを完了するか、または一部のアクションがN回完了するまで、1つのスレッドを待機させることができます。」
Chris Morris

あなたが正しいです。これは、これが私が見たCountDownLatchの最も一般的な使用法であるか、それが意図された使用法であるかを反映するために、少し答えを更新します。
James Schek、2013

11
これは、CountDownLatchの最も頻繁に使用されるものは何ですかという質問に答えます。セマフォよりもCountDownLatchを使用する利点/違いに関する元の質問には答えません。
Marco Lackovic 2013

67

CountDownLatchは、一連のスレッドを開始し、すべてのスレッドが完了するまで(またはcountDown()指定された回数だけ呼び出されるまで)待機するために使用されます。

セマフォは、リソースを使用している並行スレッドの数を制御するために使用されます。そのリソースは、ファイルのようなものにすることも、実行するスレッドの数を制限することでCPUにすることもできます。セマフォのカウントは、さまざまなスレッドがacquire()とを呼び出すにつれて増減しますrelease()

あなたの例では、あなたは本質的にセマフォを一種のカウントアップラッチとして使用しています。すべてのスレッドが終了するのを待つことがCountdownLatch目的なので、を使用すると、目的が明確になります。


22

短い要約:

  1. セマフォCountDownLatchは異なる目的で使用されます。

  2. リソースへのスレッドアクセスを制御するには、セマフォを使用します。

  3. 使用する CountDownLatchをすべてのスレッドの完了を待機する

javadocsからのセマフォの定義:

A セマフォは許可のセットを維持します。パーミットが利用可能になるまで、それぞれのquire()は必要に応じてブロックし、許可を取得します。各 release()は許可を追加し、ブロッキングアクワイアラを解放する可能性があります。

ただし、実際の許可オブジェクトは使用されません。のセマフォは、単に利用可能数のカウントを保持し、それに応じて動作します。

それはどのように機能しますか?

セマフォは、リソースを使用している並行スレッドの数を制御するために使用されます。そのリソースは、共有データやコードブロック(クリティカルセクション)、または任意のファイルのようなものです。

セマフォのカウントは、異なるスレッドがacquire()およびrelease()をます。ただし、どの時点でも、セマフォカウントを超えるスレッド数を設定することはできません。

セマフォの使用例:

  1. ディスクへの同時アクセスを制限する(これにより、ディスクシークが競合するため、パフォーマンスが低下する可能性があります)
  2. スレッド作成制限
  3. JDBC接続プール/制限
  4. ネットワーク接続スロットル
  5. CPUまたはメモリを集中的に使用するタスクの抑制

この記事をご覧くださいセマフォの使用はをご覧。

javadocsからのCountDownLatch定義:

他のスレッドで実行されている一連の操作が完了するまで、1つ以上のスレッドが待機できるようにする同期補助。

それはどのように機能しますか?

CountDownLatchは、スレッドがその実行を完了するたびに減少するスレッドの数で初期化されるカウンターを持つことによって機能します。カウントがゼロに達すると、すべてのスレッドが実行を完了し、ラッチを待機しているスレッドが実行を再開します。

CountDownLatchの使用例:

  1. 最大の並列処理を実現する:最大の並列処理を実現するために、多くのスレッドを同時に開始したい場合があります。
  2. 実行を開始する前にN個のスレッドが完了するまで待機します
  3. デッドロック検出。

この記事をご覧くださいCountDownLatchの概念を明確に理解をご覧。

この記事でFork Join Poolご覧くださいCountDownLatchといくつかの類似点があります。


7

フォーサムを見つけることを望んで、ゴルフプロショップに足を踏み入れたとしましょう。

あなたがプロショップアテンダントの1人からティータイムを取得するために並んでいる場合、基本的にはと呼ばれproshopVendorSemaphore.acquire()ますproshopVendorSemaphore.release()。ティータイムを取得すると、と呼ばれます。注:無料のアテンダントなら誰でもサービスを提供できます。つまり、共有リソースです。

今、あなたはスターターまで歩いて、彼が始まりCountDownLatch(4)との通話をawait()あなたがチェックインされたというあなたの部分のために、すなわち、他の人を待ちますCountDownLatchcountDown()残りのフォーサムも同様です。すべてが到着すると、スターターが先に進みawait()ます(コールが戻ります)

今、あなたがそれぞれ休憩を取るときに9つのホールがあった後、仮説的に再びスターターを巻き込むことができます。彼は「新しい」を使用CountDownLatch(4)してホール10をティーオフし、ホール1と同じ待機/同期を行います。

ただし、スターターCyclicBarrierが最初にa を使用した場合、&スローを使用する2番目のラッチの代わりに、ホール10で同じインスタンスをリセットすることができます。


1
私はあなたの答えを理解しているのかわかりませんが、CountdownLatchとSemaphoreがどのように機能するかを説明しようとしている場合、それは質問の主題ではありません。
finnw 2013

10
残念ながら、ゴルフについては何も知りません。
リングベアラー

しかし、スターターは.acquire(players)を使用して同様に実行でき、リリースとともにリリース数を増やします。countdownlatchは機能が少なく、再利用できないようです。
Lassi Kinnunen

1

自由に利用できるソースを見ると、2つのクラスの実装に魔法はないため、2つのクラスのパフォーマンスはほぼ同じになるはずです。意図をより明確にするものを選択してください。


0

CountdownLatchawait()カウントがゼロに達するまで、スレッドをメソッドで待機させます。つまり、何かの3回の呼び出しまですべてのスレッドを待機させて、すべてのスレッドが実行できるようにする必要があるかもしれません。あLatch一般的にリセットすることはできません。

A Semaphoreは、スレッドが許可を取得できるようにします。これにより、一度に実行するスレッドが多すぎないようにし、続行するために必要な許可を取得できない場合はブロックします。許可をに戻しSemaphore、他の待機中のスレッドの続行を許可できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.