くっそーこのテストコードじゃ再現せんぞ。
public class ThreadTest extends Thread { private int id = 0; private ThreadTest th = null; public static void main(String [] args) { ThreadTest test = new ThreadTest(); test.process(); } public int getTestId() { return this.id; } public void setTestId(int id) { this.id = id; } public ThreadTest getThread() { return this.th; } public void setThread(ThreadTest th) { this.th = th; } public void process() { System.out.println("process start."); ThreadTest th = new ThreadTest(); th.setThread(this); th.start(); setTestId(0); while (true) { if (getTestId() > 0) { break; } } System.out.println("process finish."); } public void run() { System.out.println("thread start."); try { // フラグ書き換え getThread().setTestId(1); } catch (Exception e) { e.printStackTrace(); } System.out.println("thread finish."); } }
自分のPCでも、実際現象が発生するサーバでも正常に動作しやがる。
Windowsのコマンドプロンプトから実行したからか?
サービスでJavaが動くときってそんなに違うもんなんか?
ということで、実際のコードのsleepを削除して、volatileを追記してOKなことを確認。
とりあえず実際のコードで試したらこんな結果に。
NG | private int id = 0; |
OK | private volatile int id = 0; |
OK | private static int id = 0; |
static変数にvolatile付けてもOKなんで、Singletonな扱いの変数なんかも含めて、マルチスレッドなアクセスが必要な場合はvolatileを付けるということで。
最適化されても正常に動作せんと意味ないからね。
[関連]http://d.hatena.ne.jp/S_a_k_U/20070707/p3
[関連]http://d.hatena.ne.jp/S_a_k_U/20070706/p1
[関連]http://d.hatena.ne.jp/S_a_k_U/20070617/p2