- %%2010-09-11 14:00〜 上野予定%% 延期
- 2011-02-27 14:00〜 上野予定。題材は並行処理、他を予定。
- 秋葉原開催。参加人数5名。
- 10章並行性を中心に読み進めた。synchronized, volatileの話に入るには前提条件としてJVMのメモリーキャッシュの話があると理解が早かった。その値への書き込みが単一スレッドからのみに限定されており、別スレッドからの読み込みにキャッシュを参照させたくない場合はvolatileで良い。でも単一スレッドからのみ書き込みしますという言語的宣言はJavaだとできないんだよね。なのでこの辺はドキュメントだよりになるね。
- アトミック性とはなにか、有名なところではインクリメント演算子やlong, doubleの代入はアトミックにならない、などの話。
- SimpleDateFormatの使い方についてのお説教。SimpleDateFormatは内部に状態を持ち、同期化されないのでformat()やparse()などをマルチスレッドでアクセスした場合、結果は壊れる可能性がある。
private static final DateFormat df = new SimpleDateFormat("yyyy/MM/dd"); // oh no!
-- 代わりにapache-commons-langのFastDateFormat使いましょう。
日付フォーマットは同期化されません。スレッドごとに別のフォーマットインスタンスを作成することをお勧めします。
複数のスレッドがフォーマットに並行してアクセスする場合は、外部的に同期化する必要があります。
JavaDoc 6 より http://java.sun.com/javase/ja/6/docs/ja/api/java/text/SimpleDateFormat.html
- 例題、GUIアプリ等でよくある、メインスレッドとイベントスレッドの2つの間で確実にデータを受け渡すにはどうしたらいいか。スタートボタンを押したときにMenuStatusのstartButtonPushedフラグをtrueにしてみよう。
public class MenuStatus {
private boolean startButtonPushed = false; // volatileなくて良い
public synchronized void setStartButton(final boolean value) {
startButtonPushed = value;
}
public synchronized boolean isStartButtonPushed() { // ゲッターもsynchronized掛かっていることに注目
return startButtonPushed;
}
- セッターにつけたsynchronizedはわかりやすい。オブジェクトに対するロック(モニタ)を取得し、同時に単一スレッドのみが書き込みを行うようにするためのガード。ゲッターにもsynchronizedが着いてる理由はなぜかな?これが重要。
- ここで、MenuStatusインスタンスに対して、フラグを精査し、falseであれば更新を行うという処理を書くとしよう。たしかにセッターもゲッターもsynchronizedではあるのだが2つの呼び出しはアトミックでないため、精査終わった時には状態が変わっている可能性がある。
public class Test {
public void doUpdate() {
if (!menuStatus.isStartButtonPushed()) { // ここで調べた内容は
menuStatus.setStartButton(true); // ここに来るまでに何者かにより変更されている可能性がある
}
}
}
- こういう場合はMenuStatus内にアトミックな処理として実装するのがいいでしょう。