訂正:umyuさんご指摘の点を訂正します。
Thread.sleepやTimerを使って待たなければwhile文を抜け出すことはできないのでしょうか?
いえ、必ずしもそうではありません。質問者さんのコードの詳細が不明なので抜け出せなかった原因をはっきりと指摘できませんが、~~少なくともTest.flag
はvolatile修飾子を付与しなければなりません。~~例えば、Test.flag
にvolatile
修飾子を付与するといった「実行順序の同期に関する配慮」をしなければなりません。理由については「メモリバリア」「メモリフェンス」といった用語を調べるとよいと思います。
java
1class Test {
2 static volatile boolean flag;
3 ...
4}
ただ通常はご質問のような方法(CPUを消費し続けながら期待する状態変化を検出すること=ビジーループ)は使いません。そうではなく「変化がおきるまでスレッドをブロックしてくれるような機構」を用います。Javaでそれを行う最も原始的な方法はsynchronized文
、Object#wait
、Object#notify
になります。
java
1class Test {
2 Object lock = new Object(); // 参照型のインスタンスなら何でもよい
3 boolean state; //(注)
4
5 // 状態を変更する側(スレッド#1で動かす)
6 void change() throws InterruptedException {
7 synchronized (lock) {
8 state = true;
9 lock.notify();
10 }
11 }
12
13 // 状態変化を待つ側(スレッド#2で動かす)
14 void waitForChange() throws InterruptedException {
15 synchronized (lock) {
16 while (!state) {
17 lock.wait();
18 }
19 }
20 }
21 ...
22}
(注:元の回答ではvolatileを付与していましたが、stateのread/writeが必ずsynchronizedブロック内にしかない上のような例ではvolatileは必要ないので上の例からvolatileを取りました)
lockはどんな参照型インスタンスでもよく、上の例では例えばthisとかTest.classを使ってもかまいません。thisを使うなら
java
1 void synchronzied change() throws InterruptedException {
2 state = true;
3 lock.notify();
4 }
と書けますしTest.classを使うなら
java
1 static void synchronzied change() throws InterruptedException {
2 state = true;
3 lock.notify();
4 }
と書けます。一定時間sleepなどで待機しながら変化を待つこともできますが、「状態が変化してもsleepで待っている間は変化を検知できないので即時性に劣る方法」ということになります。