Java並行処理プログラミング読書メモ
1章
スレッドセーフが必要な箇所
- Java.util.Timerが呼び出すタスクおよび、そのアクセスするクラスすべて
- サーブレット・JSP
- フィルタ・ServletContextやHttpSessionに保存するオブジェクト
- RMIのオブジェクト
- SwingとAWT
HttpSessionに保存するオブジェクトやRMIのオブジェクト等は、スレッドセーフを意識していないケースも多いのでは?
2章
- 重要なのは共有される可変なステートへのアクセス
- あるステート変数に複数スレッドがアクセスし、どれかのスレッドが変数への書き込みをする可能性があるなら、すべてのスレッドに対して同期化が必要
- TSなクラス=どういう平行状態でアクセスされてもTSになるクラス(そのクラスを使う側ではTS化について考えなくてもいい)
- check-then-actによる競り合い状態…if nullの単純なlazyInitialize(遅延初期化)では競り合いが起きる
- java.util.concurrent.atomic.AtomicLong等のThreadSafeなオブジェクトで状態を持てば、ThreadSafeなクラスに
- Javaのロックは再入可で、ロックを持っているスレッドがまたロックを取得することはOK
- syncronized(obj) { ...}では、{...}を1スレッドだけが実行できるようにobj固有のロックを使うという意味。obj自体をロックするわけではない!!
「Javaのロックは再入可」というのは知らなかった。とすると、メソッドを再帰でコールしても待つことなくロックが取得できるということか。
3章 可視化
- TSにしていない場合、別のスレッドが更新した値を、オブジェクトを共有している別のメソッドが即見られるとは限らない
- 揮発性変数(volatile):ロックは実行しないが、レジスタにキャッシュはしない変数。ロックを使うよりは軽く、可視性を保障できる
- 良い使い方:変数自身やそれが参照するオブジェクトのステートの可視性を確保
- 重要なライフサイクルイベント(初期化など)を知らせる
- デバッグ時には-serverをつけること。JVMの最適化が多く行われるため
- 初期のJVMではループ内でループ変数が変えられていないと最適化して無限ループにしていた…
可視性や、最適化による予期しない動作の話は、目から鱗。