[解決済み] Java の ThreadLocal はどのように実装されているのでしょうか?
質問
ThreadLocalはどのように実装されていますか?Java で実装されているのか (ThreadID からオブジェクトへの並列マップを使用)、それともより効率的に行うために JVM フックを使用しているのでしょうか?
どのように解決するのですか?
ここにある回答はすべて正しいのですが、少し残念なのは、いかに賢いか、ということを多少ごまかしながら
ThreadLocal
の実装がいかに巧妙であるかを隠してしまうからです。 私はちょうど
のソースコードを見ていたら
ThreadLocal
で、その実装方法に快く感心しました。
ナイーブな実装
もし、私があなたに
ThreadLocal<T>
クラスを実装するように言われたら、あなたはどうしますか? 最初の実装はおそらく
ConcurrentHashMap<Thread,T>
を使用して
Thread.currentThread()
をキーとして使用します。 これはそれなりにうまくいくでしょうが、いくつかの欠点があります。
-
スレッドの競合
ConcurrentHashMap
は非常にスマートなクラスですが、最終的にはまだ、複数のスレッドが何らかの方法でそれを操作するのを防がなければならず、異なるスレッドが定期的にそれをヒットする場合、スローダウンが発生します。 - スレッドが終了して GC した後でも、スレッドとオブジェクトの両方へのポインタを永続的に保持します。
GCフレンドリーな実装
もう一度、ガベージコレクションの問題に対処するために 弱参照 . WeakReferences の扱いはわかりにくいかもしれませんが、このように作られたマップを使えば十分でしょう。
Collections.synchronizedMap(new WeakHashMap<Thread, T>())
あるいは グアバ (を使っている場合(そうすべきです!)。
new MapMaker().weakKeys().makeMap()
これは、誰もスレッドを保持しなくなったら(つまり終了したら)、キーと値をガベージコレクションできることを意味します。これは改善されましたが、まだスレッドの競合の問題には対処できていません。
ThreadLocal
はそれほど素晴らしいクラスではないということです。 さらに、もし誰かが
Thread
オブジェクトを保持することを決めた場合、それらは決して GC'ed されず、したがって私たちのオブジェクトも、今は技術的に到達不可能であるにもかかわらず、GC'ed されないでしょう。
巧妙な実装
私たちが考えてきたのは
ThreadLocal
をスレッドから値へのマッピングとして考えてきましたが、実はそれは正しい考え方ではないかもしれません。 各 ThreadLocal オブジェクトのスレッドから値へのマッピングとして考えるのではなく、ThreadLocal オブジェクトから値へのマッピングとして考えたらどうでしょうか。
を各スレッド
? 各スレッドがマッピングを保存し、ThreadLocal が単にそのマッピングへの素晴らしいインターフェイスを提供するなら、以前の実装のすべての問題を回避することができます。
実装は次のようなものになります。
// called for each thread, and updated by the ThreadLocal instance
new WeakHashMap<ThreadLocal,T>()
このマップにアクセスするスレッドは1つだけなので、並行処理について心配する必要はありません。
彼らはThreadクラスを直接開発し、それにフィールドや操作を追加することができますし、それはまさに彼らが行ったことです。
で
java.lang.Thread
には、次のような行があります。
/* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null;
コメントからわかるように、このマッピングは実際に
ThreadLocal
オブジェクトによって追跡されるすべての値のパッケージ・プライベート・マッピングです。
Thread
. の実装は
ThreadLocalMap
は
WeakHashMap
ではありませんが、弱参照によるキーの保持を含め、同じ基本的な契約に従っています。
ThreadLocal.get()
はこのように実装されます。
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }
そして
ThreadLocal.setInitialValue()
のように
private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; }
基本的に、マップを使用する
をこのスレッドで
を使用して、すべての
ThreadLocal
オブジェクトを保持します。 この方法では、他のスレッド (
ThreadLocal
は現在のThreadの値にしかアクセスできません)、したがって、同時実行の問題はありません。 さらに、いったん
Thread
が終了すると、そのマップは自動的にGCされ、すべてのローカルオブジェクトはクリーンアップされます。 たとえ
Thread
が保持されている場合、その
ThreadLocal
オブジェクトは弱い参照で保持され、そのオブジェクトを削除すると同時に
ThreadLocal
オブジェクトがスコープ外に出た時点でクリーンアップされます。
言うまでもなく、私はこの実装にかなり感銘を受けました。これは非常にエレガントに多くの並行処理の問題を回避し (確かにコア Java の一部であることを利用していますが、これは非常に賢いクラスなので許せます)、一度にひとつのスレッドがアクセスする必要があるオブジェクトへの高速かつスレッドセーフなアクセスを可能にします。
tl;dr
ThreadLocal
の実装はかなりクールで、一見して思ったよりずっと速い/賢いです。
この回答が気に入ったのであれば、私の (あまり詳細ではない)
の議論も評価できるでしょう。
ThreadLocalRandom
.
Thread
/
ThreadLocal
から引用したコードスニペット
Oracle/OpenJDKのJava 8の実装
.
関連
-
[解決済み] 他のスレッドからGUIを更新するにはどうすればよいですか?
-
アクセス制限です。タイプ 'Application' は API ではない(必要なライブラリに制限がある)。
-
executeQuery()でデータ操作文が発行できない。解決方法
-
[解決済み] Javaの「for each」ループはどのように機能するのですか?
-
[解決済み] 整数の平方根が整数であるかどうかを判断する最速の方法
-
[解決済み] ThreadLocal変数はいつ、どのように使用すればよいですか?
-
[解決済み] 静的変数が悪とされるのはなぜですか?
-
[解決済み] Javaでリストを反復処理する方法
-
[解決済み】Javaの「ダブルブレース初期化」の効率化?
-
[解決済み】array[idx++]+="a "は、Java 8ではidxを1回増やすが、Java 9と10では2回増やすのはなぜか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
ajax コミット リソースの読み込みに失敗しました: サーバーはステータス 400 で応答しました ()
-
Uncaught ReferenceError: は定義されていません。
-
JAVA_HOME環境変数が正しく定義されていない問題を解決する
-
maven レポート エラー 解決不可能な親POM
-
Javaがリソースリークに遭遇した:'input'が閉じない 解決方法
-
Java JDKのダイナミックプロキシ(AOP)の使用と実装の原理分析
-
Java の double データ型における 0.0 と -0.0 の問題
-
htmlとwordの相互変換の実装(画像あり)
-
swagger2 モデルが表示されない モデルが見つからない @ApiModel アノテーションが表示されない問題
-
CAS 5.1.8でhttpをサポートし、認証されていない認可サービスエラーのプロンプトが表示される問題を解決した。