Date post: | 30-Jun-2015 |
Category: |
Documents |
Upload: | minoru-nakamura |
View: | 1,411 times |
Download: | 4 times |
Java のスレッド排他機構• Object はすべて同期オブジェクトになれる– Critical section 型の排他処理– 再帰的なロックも可能
• 文法– synchronized メソッド– Synchronized 文• バイトコードレベルでは monitorenter 、
monitorexit
– wait & notify
2
Java Synchronization の問題点• 安易に書けるため使いすぎる– 不要な場所にも synchronized を書いてしまう。– 衝突しない synchronization が異常に多い。
3
class Hoge { int _hoge; public synchronized int getHoge() { return _hoge; } public synchronized void setHoge(int hoge) { _hoge = hoge; } }
Java Synchronization の実装方法• 基本 (Biased Locking 以前 )– -XX:-UseBiasedLocking
• Biased Locking– -XX:+UseBiasedLocking(OpenJDK6 ではデフォル
ト )
4
Hotspot の lock 関係のオプション
-XX:+UseBiasedLocking BiasedLocking を有効に。-XX:-TraceMonitorInflation Inflation/deflation 発生時にトレースを表示。-XX:-TraceBiasedLocking BaisedLocking に変更にトレースを表示。-XX:BiasedLockingStartupDelay=4000 VM 起動後に時間をおいてから biased locking
を有効化する。その待機時間をミリ秒で指定。-XX:BiasedLockingBulkRebiasThreshold=20 Threshold of number of revocations per type to
try to rebias all objects in the heap of that type-XX:BiasedLockingBulkRevokeThreshold=40 Threshold of number of revocations per type to
permanently revoke biases of all objects in the heap of that type
-XX:BiasedLockingDecayTime=25000 Decay time (in milliseconds) to re-enable bulk rebiasing of a type after previous bulk rebias
-XX:-PrintBiasedLockingStatistics Print statistics of biased locking in JVM
5
基本ロック
6
基本ロックの方針• 衝突しないロック (uncontened lock) を効率的
に処理する• Phase1 (Lightweight) Locked– Unlock 状態のオブジェクトに最初のスレッドが
ロックを行った状態。– Thread-local なデータ構造だけで対応。
• Phase2 Inflated– 第二以降のスレッドがロックを行い、 thread-
global なデータ構造に変更する。これを inflationと呼ぶ。
7
ロックの構造体はどこにある?• oop の中にはない。• oop の第一ワードの _mark は多目的用途で、
ロック時には切り替える (markOop.hpp)
8
Fields
_klass
_mark hash code age 0 01
Pointer to basic lock 00
Pointer to monitor 10
Locked
Normal(unlocked)
Inflated lock
JavaThread* age 1 01 Biasedepoch
Phase 1 • 最初のスレッドのロックは locked状態へ遷移
– Interpreter frame 上に BasicObjectLock を積むことでロックを表現– 元の _mark の内容を _displaced_header へ退避– _mark は BasicLock の位置を Comapre-And-Swap(CAS) で書き込む。
9
Fields
_klass
To basic lockBasicObjectLock
Object
_lock : BasicLock
_obj
_displaced_header
00BasicLock
Interpreter frame
Phase 1
• 処理コード
• Recursive lock は?– Interpreter frame に複数の BasicObjectLock を積むことで実現。
• Unlock は– Stack unwind + α が unlock 処理。– ObjectSynchronizer::fast_exit
10
InterpreterRuntime::monitorenter in interpreterRuntime.cpp:585 ObjectSynchronizer::fast_enter in synchronizer.cpp:155 ObjectSynchronizer::slow_enter in synchronizer.cpp:201
Under src/share/vm/runtime/
Phase2
11
Fields
_klass
To monitor _object
_header
_recursions
_owner
10
_cxq_cxq
_EntryList
ObjectMonitorObject
…
前にあった _mark を保存ロック対象の oop
ロックオーナーロックの再帰回数 ( 初回は 0)
_prev
_next
…_thread
ObjectWaiterOwning Thread
_prev
_next
…_thread
ObjectWaiter
Blocked Thread
Blocked Thread
Phase2
• 処理コード– ObjectSynchronizer::inflate (inflation 処理 )– ObjectMonitor::enter (inflation 後のロック処理 )
• 複数のスレッドが同時に inflation を試みることがあるが、 object の _mark を CAS で書き換えることで衝突判定している。
• ObjectMonitor はスレッド毎に free list 管理されており inflate を実行しているスレッドが供出する。– ObjectSynchronizer::omAlloc
12
Biased Locking
13
Biased Locking のコンセプト• もっと CAS 命令の削除を– 基本ロックでは 1 回のロックで最低 1 回の CAS
命令を使う。• Biased Locking [Russell06]– あるスレッドからロックされたオブジェクトは、
また同じスレッドからロックされる傾向がある。– オブジェクトの中にスレッド情報を埋め込んで、
特定のスレッドに偏っている (biased) ことを示す。そのスレッドからのロックは CAS なしで済ませることが可能に。
14
Biased Locking のコンセプト• どこに biased thread を挿れるのか?– hash code を潰す。
– hashcode のフィールドは初期値は 0 で、 hashが最初に呼ばれた時に動的に設定される。• hash() が呼ばれると biased は解ける。
15
hash code age 0 01 Normal(unlocked)
Thread id age 1 01 Biasedepoch
Biased Locking のコンセプト• オブジェクト生成時は anonymously biased• 最初のスレッドがロックすると、そのスレッドの bias がかかる ( ここは CAS
が必要 )• Biased のかかったスレッドがロックする場合は _mark に変更が不要
– store-free- biased locking• ロックの衝突やその他が起きると bias をかけるのを止めて通常の状態に戻る。
– 以降、基本ロックを使用して元には戻らない。
16
0 1 01 T 1 01 … 0 01
anonymously biased biased toward given thread
… 0 00
bulk rebias
Initial lock
Revoke bias
Biasable Mode Normal Mode
Store-free biased locking(SFBL)
17
BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attempt_rebias, TRAPS) { markOop mark = obj->mark(); if (mark->is_biased_anonymously() && !attempt_rebias) { // 初めてのロック } else if (mark->has_bias_pattern()) { Klass* k = Klass::cast(obj->klass()); markOop prototype_header = k->prototype_header(); if (!prototype_header->has_bias_pattern()) { // このクラスでは biased locking が許可されていない return BIAS_REVOKED; } else if (prototype_header->bias_epoch() != mark->bias_epoch()) { // epoch が一致しないので rebiased するか revoke する retrun } }
HeuristicsResult heuristics = update_heuristics(obj(), attempt_rebias); if (heuristics == HR_NOT_BIASED) { return NOT_BIASED; // biased lokcing に成功 }
Bulk rebiasing and revocation
• Bulk rebiasing– どのスレッドで bias をかければいいのか時間
変化するので、一定周期で biased toward given thread を anonymously biased に戻す。
• Bulk revocation– ある種のオブジェクトは biased locking に向か
ない。
18
もっと CAS 命令を減らしたい
19
Synchronized getter は CAS を使わない
• Software Optimistic Lock Elision for Read-Only ciritical sections(SOLERO) [Nakaie10]– Object のヘッダにカウンタを用意– JIT を使って解析• オブジェクトのフィールドを変更する sync. method
は couner をアトミックに +1• オブジェクトのフィールドを変更しない sync.method
は counter 読む→フィールド読む→ counter 再読み込みする。• Counter が一致すれば成功。不一致なら通常の
synchronization 方式で再実行20
Counter bits xx
Synchronized getter は CAS を使わない
21
class Hoge {
int _hoge; public synchronized int getHoge() { return _hoge; }
public synchronized void setHoge(int hoge) { _hoge = hoge; }
}
class Hoge { <<counter>> int _hoge; public synchronized int getHoge() { old = counter; ret = _hoge; if (old == counter) return ret; // 再実行 } public synchronized void setHoge(int hoge) { fetchadd counter +1 _hoge = hoge; }}
参考文献• David Dice, “Implementing fast Java monitors with
relaxed locks”, In proceedings of the Java Virtual Machine, Research and Technology Symposium(JVM’01), April 2001, pp.79-90.
• Kenneth Russell and David Detlefs, “Eliminating Synchronization-Related Atomic Operations with Biased Locking and Bulk Rebiasing”, OOPSLA’06, pp.
• Takuya Nakaike and Maged M. Michael, “Lock Elision for Read-Only Critical Section in Java”, PLDI’10
22