javaでは、あるオブジェクトに対して複数スレッドが同時にオブジェクトの状態を変更することができないようにするしくみとして待機と通知というのがあります。
待機 とは、スレッドであるオブジェクトをロックして、別スレッドから通知されるまで、スレッドの処理を一時停止することを言います。
待機状態になった際、オブジェクトのロックは解除されます。これは、別スレッドからオブジェクトの状態を変更できるようにするためこのようなしくみになっています。
待機はObjectクラスの
wait() メソッドで実行します。
obj.wait(); という感じで実行します。このとき、objはロックされている必要があります。
以下を見てください。synchronizedブロックでobjをロックしています。
public class TEST {
public static void main(String[] args){
Object obj = new Object();
System.out.println("a");
synchronized(obj){
try {
System.out.println("a");
obj.wait();
System.out.println("b");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
このクラスを実行すると、以下のような結果になります。
出力結果から見てわかるように、wait()メソッド実行後、スレッドは一時停止されたままになります。
a
a
このままではプログラムは停止したままになります。これでは困るので、wait()メソッドの引数に秒数を指定します。単位はミリ秒です。
秒数を指定すると、指定した秒数一時停止し、再びスレッドが続行されます。
以下例を見てください。これは上記例のwait()メソッドに秒数を指定しただけです。
public class TEST {
public static void main(String[] args){
Object obj = new Object();
System.out.println("a");
synchronized(obj){
try {
System.out.println("a");
obj.wait(4000);
System.out.println("b");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
このクラスを実行すると、以下のような結果になります。
実際実行するとわかりますが、aが2回出力されて4秒後にbが出力されます。
a
a
b
このように秒数を指定することで待機状態を解除することができます。また、通知というしくみを使用することによっても待機状態を解除することができます。
通知 とは、スレッドであるオブジェクトをロックして、そのオブジェクトに対して待機(一時停止)している別スレッドに対して処理続行を通知することをいいます。
通知はObjectクラスの
notify() メソッド、またはObjectクラスの
notifyAll() メソッドを実行します。
obj.notify(); という感じで実行します。このとき、objはロックされている必要があります。
notify()メソッドを実行後、objに対して待機している別スレッドに対して通知をおこないます。そしてobjのロックを解除(例の場合synchronizedブロックを終了するとロック解除される)したら、objに対して待機している別スレッドがobjを再びロックして処理を続行します。
これに対し、notifyAll()メソッドは複数待機しているスレッドが存在する場合に実行すると、全ての待機待ちスレッドが処理続行されます。