「Javaのスレッドのwait、notify、notifyAllの例」
JavaのObjectクラスには、スレッドがリソースのロック状態について通信するための、wait()、notify()、notifyAll()という3つの最終メソッドが含まれています。ですので、今日はJavaプログラム内でのwait、notify、notifyAllについて見ていきます。
Javaにおけるwait、notify、notifyAllについて待っている。
これらのメソッドをオブジェクト上で呼び出している現在のスレッドは、オブジェクトのモニターを持っていない場合、java.lang.IllegalMonitorStateException例外をスローします。
待ってください。
オブジェクトの待機メソッドには3つのバリエーションがあります。1つは、他のスレッドがオブジェクトにnotifyまたはnotifyAllメソッドを呼び出して現在のスレッドを起こすまで、無期限に待機します。他の2つのバリエーションは、特定の時間だけ待機してから起きるように、現在のスレッドを待機状態にします。
通知する
notifyメソッドは、オブジェクトで待機しているスレッドを1つだけ起こし、そのスレッドが実行を開始します。したがって、1つのオブジェクトに対して複数のスレッドが待機している場合、このメソッドはその中の1つのスレッドだけを起こします。起こすスレッドの選択は、OSのスレッド管理の実装に依存します。
全員に通知する
notifyAllメソッドは、オブジェクトで待機しているすべてのスレッドを起こしますが、どのスレッドが最初に処理されるかはOSの実装に依存します。これらのメソッドは、キュー内のオブジェクトを待機しているコンシューマースレッドと、キューにオブジェクトを投入して待機しているスレッドをお知らせするために使用することができます。同じオブジェクトで複数のスレッドが作業する例を見てみましょう。wait、notify、およびnotifyAllのメソッドを使用します。
メッセージ
スレッドで動作し、waitメソッドとnotifyメソッドを呼び出すJavaビーンクラス。
package com.scdev.concurrency;
public class Message {
private String msg;
public Message(String str){
this.msg=str;
}
public String getMsg() {
return msg;
}
public void setMsg(String str) {
this.msg=str;
}
}
ウェイターさん
Waiter+sさん
お待ちしております
他のスレッドが notify メソッドを呼び出すのを待つクラス。注意:Waiter スレッドは、synchronized ブロックを使用して Message オブジェクトのモニターを所有しています。
package com.scdev.concurrency;
public class Waiter implements Runnable{
private Message msg;
public Waiter(Message m){
this.msg=m;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
synchronized (msg) {
try{
System.out.println(name+" waiting to get notified at time:"+System.currentTimeMillis());
msg.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(name+" waiter thread got notified at time:"+System.currentTimeMillis());
//process the message now
System.out.println(name+" processed: "+msg.getMsg());
}
}
}
通知者
Messageオブジェクトに処理を施すクラスであり、そしてnotifyメソッドを呼び出してMessageオブジェクトを待ち状態から起こすことができるクラスです。ただし、Messageオブジェクトのモニターを所有するために、synchronizedブロックが使用されていることに注意してください。
package com.scdev.concurrency;
public class Notifier implements Runnable {
private Message msg;
public Notifier(Message msg) {
this.msg = msg;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name+" started");
try {
Thread.sleep(1000);
synchronized (msg) {
msg.setMsg(name+" Notifier work done");
msg.notify();
// msg.notifyAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
待機通知テスト
複数のWaiterとNotifierのスレッドを作成し、それらを開始するテストクラスを作成します。
package com.scdev.concurrency;
public class WaitNotifyTest {
public static void main(String[] args) {
Message msg = new Message("process it");
Waiter waiter = new Waiter(msg);
new Thread(waiter,"waiter").start();
Waiter waiter1 = new Waiter(msg);
new Thread(waiter1, "waiter1").start();
Notifier notifier = new Notifier(msg);
new Thread(notifier, "notifier").start();
System.out.println("All the threads are started");
}
}
上記のプログラムを呼び出すと、以下の出力が表示されますが、プログラムは完了しません。なぜなら、Messageオブジェクトに待機しているスレッドが2つあり、notify()メソッドはそのうちの1つしか起こさず、もう1つのスレッドはまだ通知を待っているからです。
waiter waiting to get notified at time:1356318734009
waiter1 waiting to get notified at time:1356318734010
All the threads are started
notifier started
waiter waiter thread got notified at time:1356318735011
waiter processed: notifier Notifier work done
ノーティファイヤークラスのnotify()呼び出しのコメントを外し、notifyAll()呼び出しのコメントを外すと、以下の出力が生成されます。
waiter waiting to get notified at time:1356318917118
waiter1 waiting to get notified at time:1356318917118
All the threads are started
notifier started
waiter1 waiter thread got notified at time:1356318918120
waiter1 processed: notifier Notifier work done
waiter waiter thread got notified at time:1356318918120
waiter processed: notifier Notifier work done
Javaにおいて、notifyAll()メソッドは、Waiterスレッドを両方とも起こし、プログラムは実行後すぐに完了し終了します。以上が、wait、notify、およびnotifyAllに関するすべてです。