Javaのwaitは現在のスレッドを待機させたい場合に使用します。
スレッドを使用していると、他の処理が終わるまで現在のスレッドを待機させたい場合があります。
この記事では、そんなwaitについて以下の内容で解説していきます。
・waitとは
・notifyが呼び出されるまで待機
・notifyAllが呼び出されるまで待機
・Thread.sleepについて
今回はwaitについて、使い方をわかりやすく解説します!
なお、Javaの記事については、こちらにまとめています。
waitとは?
waitメソッドが呼び出されると現在のスレッドが待機状態になります。
notifyメソッド、またはnotifyAllメソッドが呼び出されるまで待機します。
スレッドとは、「複数の処理を同時並行で行える機能」と考えるとよいかと思います。
このスレッドが一列で順番に処理されていくことを、「シングルスレッド」と言います。
これに対して、スレッドの列が2つ以上複数あり並列に同時進行で処理されていくことを「マルチスレッド」と言います。
マルチスレッドで、あるスレッドの処理が終了するのを別のスレッドが待機する必要がある場合に、このwaitメソッドを使います。
waitメソッドはjava.lang.Objectクラスのメソッドです。
以下のようにtry-catch文とあわせて使われます。
try { wait(); } catch (InterruptedException e) { e.printStackTrace(); }
notifyが呼び出されるまで待機
notifyメソッドで処理を再開する方法について解説します。
notifyメソッドはwaitメソッドが呼び出され待機状態のスレッドの中の1つを再開します。
複数のスレッドが待機している場合は、その中のどれか1つのスレッドを再開します。
どのスレッドを再開するか選択することはできません。
サンプルコードで確認しましょう。
class PrintClass { synchronized void threadWait() { System.out.println("待機を開始します"); try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("待機が終了しました"); } synchronized void threadNotify() { notify(); System.out.println("待機を終了させます"); } } class ThreadWait extends Thread { private PrintClass pc; public ThreadWait(PrintClass pc) { this.pc = pc; } public void run() { pc.threadWait(); } } class ThreadNotify extends Thread { private PrintClass pc; public ThreadNotify(PrintClass pc) { this.pc = pc; } public void run() { pc.threadNotify(); } } public class WaitSample { public static void main(String[] args) { PrintClass pc = new PrintClass(); ThreadWait tWait = new ThreadWait(pc); ThreadNotify tNotify = new ThreadNotify(pc); tWait.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } tNotify.start(); } }
実行結果:
待機を開始します 待機を終了させます 待機が終了しました
synchronized修飾子が付いたメソッドをメンバに持つオブジェクトはそのメソッドを実行している間、同じオブジェクト内のsynchronized修飾子が付いたメソッドからアクセスされないようにロックされます。
このサンプルコードでは、waitメソッドをメンバに持つオブジェクトtWaitのスレッドがスタートして待機状態が開始されます。
1000ミリ秒後にnotifyメソッドをメンバに持つオブジェクトtNotifyのスレッドがスタートして待機状態が終了します。
結果「待機が終了しました」と表示する処理が実行されています。
notifyAllが呼び出されるまで待機
notifyAllメソッドで処理を再開する方法について解説します。
notifyAllメソッドはwaitメソッドにより待機状態にある全てのスレッドの処理を再開します。
サンプルコードで確認しましょう。
class PrintClass { synchronized void threadWait() { System.out.println(Thread.currentThread().getName() + "の待機を開始します"); try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "の待機が終了しました"); } synchronized void threadNotifyAll() { notifyAll(); System.out.println("全スレッドの待機を終了させます"); } } class ThreadWait extends Thread { private PrintClass pc; public ThreadWait(PrintClass pc) { this.pc = pc; } public void run() { pc.threadWait(); } } class ThreadNotify extends Thread { private PrintClass pc; public ThreadNotify(PrintClass pc) { this.pc = pc; } public void run() { pc.threadNotifyAll(); } } public class WaitSample { public static void main(String[] args) { PrintClass pc = new PrintClass(); ThreadWait tWait1 = new ThreadWait(pc); ThreadWait tWait2 = new ThreadWait(pc); ThreadWait tWait3 = new ThreadWait(pc); ThreadNotify tNotify = new ThreadNotify(pc); tWait1.start(); tWait2.start(); tWait3.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } tNotify.start(); } }
実行結果:
Thread-0の待機を開始します Thread-2の待機を開始します Thread-1の待機を開始します 全スレッドの待機を終了させます Thread-0の待機が終了しました Thread-1の待機が終了しました Thread-2の待機が終了しました
このサンプルコードでは、waitメソッドをメンバに持つオブジェクトtWait1、tWait2、tWait3のスレッドがスタートしてそれぞれの待機状態が開始されます。
1000ミリ秒後にnotifyAllメソッドをメンバに持つオブジェクトtNotifyのスレッドがスタートして全てのスレッドの待機状態が終了します。
結果、それぞれのスレッドで「待機が終了しました」と表示する処理が実行されています。
synchronized修飾子やnotifyAllメソッドの使い方については、こちらでも詳しく解説しています。
ぜひ参考にしてください。
Thread.sleepについて
Threadクラスのsleepメソッドを使って一定時間停止させることもできます。
Thread.sleepメソッドの使い方については、こちらで詳しく解説していますので、ぜひ参考にしてください。
まとめ
ここでは、スレッドについてwaitメソッドの使い方やnotify、notifyAllメソッドの使い方について説明しました。
あるスレッドの処理が終了するのを別のスレッドが待機する必要がある場合に、waitメソッドを使います。
また、待機状態から処理を再開する場合にnotify、notifyAllメソッドを使います。
スレッドは使い始めの頃は慣れずに戸惑ったりすることも多くなるかもしれませんが、そんな場合はこの記事を何度も参考にして下さいね!