Javaのwait()・notify()・notifyAll()メソッドとは?スレッド間通信の重要性を解説
Javaでは、wait()、notify()、notifyAll()という3つのメソッドを使って、スレッド同士が互いに通信(協調動作)を行うことができます。
これらのメソッドには、以下のような重要な特徴があります。
- Objectクラスで定義されたfinalメソッドであるため、すべてのクラスで利用可能
- synchronizedブロックまたはsynchronizedメソッドの中からのみ呼び出し可能
- モニター(ロック)を所有していない状態で呼び出すとIllegalMonitorStateExceptionがスローされる
各メソッドの役割
wait()メソッド
現在実行中のスレッドを待機状態にします。別のスレッドが同じオブジェクトに対してnotify()またはnotifyAll()を呼び出すまで、スレッドは待ち続けます。待機中のスレッドは、オブジェクトのモニター(ロック)を解放する点が重要です。
notify()メソッド
そのオブジェクトのモニター上で待機しているスレッドのうち、1つのスレッドだけを起床(再開)させます。どのスレッドが選ばれるかはJVMの実装に依存します。
notifyAll()メソッド
そのオブジェクトのモニター上で待機しているすべてのスレッドを起床させます。複数のスレッドが同じ条件を待っている場合に適しています。
メソッドの構文
wait()メソッド
public final void wait() throws InterruptedException
notify()メソッド
public final void notify()
notifyAll()メソッド
public final void notifyAll()
実装例:wait()とnotify()を使ったスレッド間通信
次のサンプルコードでは、メインスレッドがjoin()メソッド内でwait()によって待機し、別スレッドが処理完了後にnotify()を呼び出して通知する仕組みを示しています。
public class WaitNotifyTest {
private static final long SLEEP_INTERVAL = 3000;
private boolean running = true;
private Thread thread;
public void start() {
print("Inside start() method");
thread = new Thread(new Runnable() {
@Override
public void run() {
print("Inside run() method");
try {
Thread.sleep(SLEEP_INTERVAL);
} catch(InterruptedException e) {
Thread.currentThread().interrupt();
}
synchronized(WaitNotifyTest.this) {
running = false;
WaitNotifyTest.this.notify(); // 待機中のスレッドへ通知
}
}
});
thread.start();
}
public void join() throws InterruptedException {
print("Inside join() method");
synchronized(this) {
while(running) {
print("Waiting for the peer thread to finish.");
wait(); // runningがfalseになるまで待機
}
print("Peer thread finished.");
}
}
private void print(String s) {
System.out.println(s);
}
public static void main(String[] args) throws InterruptedException {
WaitNotifyTest test = new WaitNotifyTest();
test.start();
test.join();
}
}
実行結果
Inside start() method Inside join() method Waiting for the peer thread to finish. Inside run() method Peer thread finished.
ポイントまとめ
- wait()は必ずwhileループと組み合わせて使用するのが推奨されます。これは、スプリアスウェイクアップ(偶発的な起床)や条件の再確認に対応するためです。
- wait()を呼び出すとモニターのロックが一時的に解放され、notify()によって起床した後、再度ロックを取得して処理を再開します。
- これらのメソッドを正しく使うことで、生産者・消費者問題のようなスレッド間の協調制御を安全に実装できます。
-
Javaの同時実行性 – Thread.yield()メソッドの仕組みと使い方
yield()メソッドとはjava.lang.Thread.yield()メソッドは、現在実行中のスレッドが自発的にCPUの使用権を手放し、より優先度の高い他のスレッドに実行の機会を譲るよう、スレッドスケジューラにヒントを伝えるためのメソッドです。処理に時間がかかっている重要度の低いスレッドよりも、優先して実行すべきスレッドを先に進めたい場面で利用されます。スレッドがyield()を呼び出すと、「自分の実行を一時停止してもよい」という合図がスケジューラに送られます。ただし、この合図を受け入れるか無視するかはスケジューラの判断に委ねられており、必ず譲るとは限らない点に注意が必要です。yield(
-
Java 9のdestroyForcibly()メソッドとは?プロセスを強制終了する方法を解説
destroyForcibly() メソッドは、実行中のプロセスを強制的に終了(キル)するために使用されます。このメソッドは、プロセスが正常に終了しない場合や、フリーズ(応答停止)してしまった場合に特に役立ちます。 例えば、destroyForcibly() を呼び出した後でも isAlive() メソッドが true を返すことがあります。これは、OSレベルでの終了処理が完了するまでに時間差があるためです。また、destroyForcibly() は終了要求が正常に受け付けられた場合は true を返し、そうでない場合は false を返します。 構文 boolean destroyForc