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なメソッドをオーバーライドしていたらロックが取得できずにデッドロックになってしまう
  • syncronized(obj) { ...}では、{...}を1スレッドだけが実行できるようにobj固有のロックを使うという意味。obj自体をロックするわけではない!!

Javaのロックは再入可」というのは知らなかった。とすると、メソッド再帰でコールしても待つことなくロックが取得できるということか。

  • よく使われるロック方式(例:Vector)
    • 可変なステートをすべてひとつのオブジェクトの中へカプセル化して、可変ステートにアクセスするすべてのコードをそのオブジェクトの固有のロックを使って同期化

3章 可視化

  • TSにしていない場合、別のスレッドが更新した値を、オブジェクトを共有している別のメソッドが即見られるとは限らない
  • 揮発性変数(volatile):ロックは実行しないが、レジスタにキャッシュはしない変数。ロックを使うよりは軽く、可視性を保障できる
    • 良い使い方:変数自身やそれが参照するオブジェクトのステートの可視性を確保
    • 重要なライフサイクルイベント(初期化など)を知らせる
  • デバッグ時には-serverをつけること。JVMの最適化が多く行われるため
  • 初期のJVMではループ内でループ変数が変えられていないと最適化して無限ループにしていた…
  • コンストラクト中にthis参照を逸出してはいけない(コンストラクタでのEventListenerへの登録などはNG)

可視性や、最適化による予期しない動作の話は、目から鱗。