複数スレッドからアクセスされる変数の同期化
先日から、噂の良書「Java並行処理プログラミング」をお借りしてマルチスレッドを勉強中。
以下のコードはスレッドセーフではないけど、それはどこか?
- UnThreadSafe.java
public class UnThreadSafe{ private static boolean loopFlag = true; private static String message = "Default"; private static long count = 0; private static class Worker extends Thread { public void run(){ while(loopFlag){ count++; } System.out.println("message: " + message); } } public static void main(String[] args) throws Exception{ new Worker().start(); Thread.sleep(100); message = "Done"; loopFlag = false; } }
- (期待される)実行結果
message: Done
通常は上記のような結果が期待されるけど、実際にはこの動作になるとは限らない。
mainメソッド側のスレッドが書き込んだmessageとloopFlagは、workerスレッド側でいつ、どの順序で読み込むかは保証されていないため、loopFlagだけが先に読み込まれて"message: DEFAULT"と表示されるかもしれないし、loopFlagがいつまでもtrueでループが周り続けるかもしれない。
JVMでは、マルチプロセッサー上での効率をあげるためこのような仕様であり、同期していないオブジェクトはCPUのレジスタにキャッシュすることを許しているためらしい。
解決するにはシンプルにアクセスされる変数を同期化。
private static volatile boolean loopFlag = true; private static volatile String message = "Default";
volatileを付加することで、この変数を参照する際にはメインメモリを参照するようになり、書き込み、読み込みのタイミング、順序が保証されるようになる。
うーん、マルチスレッドはかなり複雑、、しかも無知でプログラムを組むと悲惨なことになりそう。
「Java並行処理プログラミング」はさらっと全体読んでみたけど、「ダメな例->改善した例」と実践形式でわかりやすく書かれており、読者が納得しながら読み進められるので本当に良い本だと思う。読んでいておもしろいし。なんでこれが廃盤になったのか。

Java並行処理プログラミング ―その「基盤」と「最新API」を究める―
- 作者: Brian Goetz,Joshua Bloch,Doug Lea
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2006/11/22
- メディア: 単行本
- 購入: 30人 クリック: 442回
- この商品を含むブログ (172件) を見る
とりあえず一票入れといた。↓