使用する利点はありますか
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がゼロに達したときにすべてが同時に開始する「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
を使用すると、意図が明確になります。
要約:
セマフォ と CountDownLatch は異なる目的を果たします。
Semaphoreを使用して、リソースへのスレッドアクセスを制御します。
CountDownLatchを使用して、すべてのスレッドの完了を待機します
javadocsのセマフォ定義:
Semaphoreは許可セットを保持します。各acquire()ブロックは、必要に応じてpermitが利用可能になるまでブロックし、それを取得します。各release()は許可を追加し、潜在的にブロッキング取得者を解放します。
ただし、実際の許可オブジェクトは使用されません。 Semaphoreは利用可能な数のカウントを保持し、それに応じて動作します。
どのように機能しますか?
セマフォは、リソースを使用している同時スレッドの数を制御するために使用されます。そのリソースは、共有データやコードのブロック(critical section)または任意のファイル。
セマフォのカウントは、異なるスレッドがacquire
()およびrelease
()を呼び出すと上下する可能性があります。ただし、どの時点でも、セマフォカウントより多くのスレッドを使用することはできません。
セマフォのユースケース:
セマフォの使用については、これをご覧ください 記事 .
javadocsのCountDownLatch定義:
他のスレッドで実行されている一連の操作が完了するまで、1つ以上のスレッドが待機できるようにする同期支援。
どのように機能しますか?
CountDownLatchは、スレッドの数で初期化されるカウンターを持つことにより機能し、スレッドが実行を完了するたびにデクリメントされます。カウントがゼロに達すると、すべてのスレッドが実行を完了し、ラッチを待機しているスレッドが実行を再開することを意味します。
CountDownLatchユースケース:
CountDownLatchの概念を明確に理解するには、これをご覧ください 記事 .
Fork Join Pool をご覧ください 記事 もご覧ください。 CountDownLatchといくつかの類似点があります。
ゴルフのプロショップに行って、フォーサムを見つけたいと思って、
プロショップのアテンダントの一人からティータイムを得るために並んでいるとき、本質的にproshopVendorSemaphore.acquire()
を呼び出し、ティータイムを取得したら、proshopVendorSemaphore.release()
を呼び出しました。無料のアテンダントがサービスを提供できます。つまり、共有リソースです。
さあ、あなたはスターターに近づき、彼はCountDownLatch(4)
を開始し、await()
を呼び出して他の人を待ちます。あなたがチェックインした部分、つまりCountDownLatch
.countDown()
そして、フォーサムの残りも同様です。すべてが到着すると、スターターは先に進みます(await()
呼び出しが戻ります)
今、あなたがそれぞれ休憩をとる9つのホールの後、仮説的にスターターを再び関与させ、彼は「新しい」CountDownLatch(4)
を使用して、ホール1と同じ待機/同期を行います。
ただし、スターターが最初にCyclicBarrier
を使用した場合、2番目のラッチ(&スローを使用)ではなく、ホール10の同じインスタンスをリセットできた可能性があります。
自由に利用できるソースを見ると、2つのクラスの実装に魔法はないため、パフォーマンスはほぼ同じです。あなたの意図をより明確にするものを選択してください。
CountdownLatchは、カウントがゼロに達するまでスレッドをawait()メソッドで待機させます。そのため、すべてのスレッドが何かの3回の呼び出しまで待機すると、すべてのスレッドが実行できるようになる可能性があります。通常、ラッチはリセットできません。
セマフォは、スレッドが許可を取得することを許可します。これにより、一度に実行するスレッドが多すぎることを防ぎ、続行するために必要な許可を取得できない場合はブロックします。許可はセマフォに返され、他の待機スレッドが処理を続行できるようにします。