CountDownLatch と Semaphore はどちらも Java の同期制御 を行うためのツールですが、用途や動作は異なります。ここでは、それぞれの違いと使い方について説明します。
1. Semaphore とは
Semaphore は、指定した数の「許可(permits)」を管理し、スレッドが許可の数を超えて同時にリソースにアクセスできないようにするために使います。例えば、Semaphore(3) であれば、同時に3つのスレッドまでしかリソースにアクセスできません。ある意味で「スレッドの同時アクセス制限」に適したクラスです。
特徴
許可を取得する (acquire) と、許可の数が減少します。
許可を解放する (release) と、許可の数が増加します。
同時にアクセスできるスレッド数を制御するために使われます。
使用例
import java.util.concurrent.Semaphore;
public class SemaphoreExample {
private static final Semaphore semaphore = new Semaphore(3);
public void accessResource() throws InterruptedException {
semaphore.acquire(); // 許可を取得
try {
// リソースへのアクセス
System.out.println(Thread.currentThread().getName() + " is accessing resource.");
} finally {
semaphore.release(); // 許可を解放
}
}
}
2. CountDownLatch とは
CountDownLatch は、あるスレッドが複数のスレッドの作業が完了するのを待機するために使われます。指定したカウントがゼロになるまでスレッドを待機させ、そのカウントがすべて消費されたときに他のスレッドを進行させます。ある意味で「一連のスレッドが完了するのを待つ」ために使います。
特徴
CountDownLatch は、初期化時に指定したカウントが 0 になるまで他のスレッドを待機させます。
countDown() メソッドを呼び出すことでカウントが減少し、すべてのカウントが 0 になると await() していたスレッドが進行します。
一度しか使用できません(カウントがリセットされないため)。
使用例
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
private static final CountDownLatch latch = new CountDownLatch(3);
public void performTask() throws InterruptedException {
System.out.println(Thread.currentThread().getName() + " is performing task.");
latch.countDown(); // カウントを1つ減らす
}
public static void main(String[] args) throws InterruptedException {
CountDownLatchExample example = new CountDownLatchExample();
// 3つのスレッドが実行され、各スレッドがカウントを減らす
new Thread(example::performTask).start();
new Thread(example::performTask).start();
new Thread(example::performTask).start();
// すべてのスレッドが完了するまで待機
latch.await();
System.out.println("All tasks are completed.");
}
}
3. Semaphore と CountDownLatch の違い
特徴 | Semaphore | CountDownLatch |
---|---|---|
目的 | 同時にアクセスできるスレッド数を制御 | 複数のスレッドの完了を待機 |
許可の増減 | acquire() で許可を取得、release() で解放 | countDown() でカウント減少 |
リセット | リセット 許可は解放されるたびに再利用可能 | カウントがゼロになると再利用不可 |
同時アクセス数 | 許可の数に応じてアクセス制限 | カウントに基づいて動作 |
使用例 | リソースへの同時アクセス数制限 | 一連のタスク完了を待つ |
どちらを使うべきか
同時接続数やアクセス数の制御を行いたい場合(たとえば、同時に3つのスレッドしか特定のリソースにアクセスさせたくない場合)には、Semaphore が適しています。
複数のタスクが完了するのを待って、その後で処理を進めたい場合(たとえば、全スレッドが完了するまで待機するシナリオ)には、CountDownLatch が適しています。
4. 具体的な用途の違い
Semaphore: 接続制限、スレッドプールのように同時アクセス数を制限したい場合に便利です。たとえば、Tomcat の同時接続数をアプリケーションレベルで制御したいときに使えます。
CountDownLatch: 全ての処理が完了してから次に進むといった、イベントの同期や一斉開始・終了のタイミングを合わせたい場合に有用です。たとえば、全てのスレッドが初期化された後に処理を開始するようなシナリオで使用します。
このように、Semaphore と CountDownLatch は異なる目的を持つ同期制御メカニズムです。どちらを使うかは、プロセスの同時実行制御が必要か、あるいはスレッドの完了を待機したいかによって判断します。