[Java]volatile alternate synchronized?
volatileは排他制御用の機能ではなく、変数のロード/ストアをatomicに行うための機能。synchronizedと同等に機能することを期待できるのは、参照や更新が各処理で一度だけですむ場合だけだ。この辺の考えは、
static Map syncMap = Collections.synchronizeMap(new HashMap());
static Object getCachedObject(Object key) {
if (syncMap.containsKey(key)) {
return syncMap.get(key);
} else {
Object value = new Value(key);
syncMap.put(key, value);
return value;
}
}
このコードがうまく動かないのと同じような感じだ。複数回の読み書きの間に他のスレッドが更新を行うかもしれないから。
Javaのリオーダとメモリモデルの話もある。
- リオーダ…スレッド自身にとって問題が無ければ、処理の順序は入れ替わる
- メモリモデル…スレッドは、自分用のキャッシュだけを読み書きしていることがある
例えば、
volatile static instance;
static Object getInstance() {
if (instance == null) {
insntacre = new Singleton();
}
return instance;
}
この処理はうまく動かない。
volatileを使っているので、instanceのnull判定はうまくいく。でも、new Singletonの初期化処理が終わっているかどうかは分からない。リオーダで、Singletonのコンストラクタがやっている初期化は代入より後になっているかもしれない。
初期化処理が終わっていても、Singletonクラスのインスタンスフィールドはメインメモリに書き出されていないかもしれない。volatileは変数の代入部分を書き出すことしか保障してくれない。
気の利いたVMやコンパイラなら 初期化が終わるまでインスタンスを公開しない とか、volatileを見かけたらインスタンスフィールドの書き出しを代入より先にやる ってこともやってくれる。
#new した後でinit()を呼び出して初期化 なんて変な作りならコレもダメだろうけど
この辺の話は、synchronizeを使わないと動かない。synchronizedでも動かないパターンはまた今度書こ。
JSR133でメモリモデルの仕様が見直されているので、volatileの扱いはもう少し上になる。でも、Javaがオープンソース化されて今後は大量の亜種が出回ることになるだろうから、この辺をしっかりと実装してくれるか分からない。
ラベル: Java
0 件のコメント:
コメントを投稿
登録 コメントの投稿 [Atom]
<< ホーム