スレッドローカル変数とは何ですか?
中国語に翻訳された ThreadLocal のより正確な名前は、スレッド ローカル変数です。
これは何の役に立つのですか、あるいはなぜそんなものがあるのですか?まず、並行プログラミング中、各スレッドが同じ変数を操作している場合、メンバー変数は実際にはスレッドアンセーフであることを説明します。これは明らかに不可能であり、キーワード volatile がスレッドのセキュリティを保証しないこともわかっています。安全。したがって、あるケースでは、変数は同じであるが、各スレッドは同じ初期値を使用する、つまり、同じ変数の新しいコピーを使用するという条件を満たす必要があります。この場合、ThreadLocal は非常に便利です。たとえば、DAO のデータベース接続はシングルトンであるため、その属性 Connection はスレッドセーフ変数ではありません。そして、各スレッドはそれを使用する必要があり、それぞれが独自のものを使用します。この場合、ThreadLocal はこの問題をより適切に解決します。
この問題をソースコードの観点から分析します。
最初に ThreadLocal を定義します:
ThreadLocal<Connection> tl = ThreadLocal<Connection> Connection initConn = = DriverManager.getConnection("url, name and password"=( ==
package java.lang;import java.lang.ref.*;import java.util.concurrent.atomic.AtomicInteger;public class ThreadLocal<T> { private final int threadLocalHashCode = nextHashCode(); private static AtomicInteger nextHashCode =new AtomicInteger();private static final int HASH_INCREMENT = 0x61c88647;private static int nextHashCode() {return nextHashCode.getAndAdd(HASH_INCREMENT); }protected T initialValue() {return null; }public ThreadLocal() { }public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t);if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this);if (e != null)return (T)e.value; }return setInitialValue(); }private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t);if (map != null) map.set(this, value);elsecreateMap(t, value);return value; }public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t);if (map != null) map.set(this, value);elsecreateMap(t, value); } public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); }ThreadLocalMap getMap(Thread t) {return t.threadLocals; }void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {return new ThreadLocalMap(parentMap); }T childValue(T parentValue) {throw new UnsupportedOperationException(); }static class ThreadLocalMap {static class Entry extends WeakReference<ThreadLocal> {/** The value associated with this ThreadLocal. */Object value; Entry(ThreadLocal k, Object v) {super(k); value = v; } }private static final int INITIAL_CAPACITY = 16;private Entry[] table;private int size = 0;private int threshold; // Default to 0private void setThreshold(int len) { threshold = len * 2 / 3; }private static int nextIndex(int i, int len) {return ((i + 1 < len) ? i + 1 : 0); }private static int prevIndex(int i, int len) {return ((i - 1 >= 0) ? i - 1 : len - 1); }ThreadLocalMap(ThreadLocal firstKey, Object firstValue) { table = new Entry[INITIAL_CAPACITY];int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); table[i] = new Entry(firstKey, firstValue); size = 1; setThreshold(INITIAL_CAPACITY); }private ThreadLocalMap(ThreadLocalMap parentMap) { Entry[] parentTable = parentMap.table;int len = parentTable.length; setThreshold(len); table = new Entry[len];for (int j = 0; j < len; j++) { Entry e = parentTable[j];if (e != null) { ThreadLocal key = e.get();if (key != null) { Object value = key.childValue(e.value); Entry c = new Entry(key, value);int h = key.threadLocalHashCode & (len - 1);while (table[h] != null) h = nextIndex(h, len); table[h] = c; size++; } } } }private Entry getEntry(ThreadLocal key) {int i = key.threadLocalHashCode & (table.length - 1); Entry e = table[i];if (e != null && e.get() == key)return e;elsereturn getEntryAfterMiss(key, i, e); }private Entry getEntryAfterMiss(ThreadLocal key, int i, Entry e) { Entry[] tab = table;int len = tab.length;while (e != null) { ThreadLocal k = e.get();if (k == key)return e;if (k == null) expungeStaleEntry(i);elsei = nextIndex(i, len); e = tab[i]; }return null; }private void set(ThreadLocal key, Object value) {Entry[] tab = table;int len = tab.length;int i = key.threadLocalHashCode & (len-1);for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { ThreadLocal k = e.get();if (k == key) { e.value = value;return; }if (k == null) { replaceStaleEntry(key, value, i);return; } } tab[i] = new Entry(key, value);int sz = ++size;if (!cleanSomeSlots(i, sz) && sz >= threshold) rehash(); }private void remove(ThreadLocal key) { Entry[] tab = table;int len = tab.length;int i = key.threadLocalHashCode & (len-1);for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) {if (e.get() == key) { e.clear(); expungeStaleEntry(i);return; } } }private void replaceStaleEntry(ThreadLocal key, Object value, int staleSlot) { Entry[] tab = table;int len = tab.length; Entry e;int slotToExpunge = staleSlot;for (int i = prevIndex(staleSlot, len); (e = tab[i]) != null; i = prevIndex(i, len))if (e.get() == null) slotToExpunge = i;for (int i = nextIndex(staleSlot, len); (e = tab[i]) != null; i = nextIndex(i, len)) { ThreadLocal k = e.get();if (k == key) { e.value = value; tab[i] = tab[staleSlot]; tab[staleSlot] = e;if (slotToExpunge == staleSlot) slotToExpunge = i; cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);return; }if (k == null && slotToExpunge == staleSlot) slotToExpunge = i; }tab[staleSlot].value = null; tab[staleSlot] = new Entry(key, value);if (slotToExpunge != staleSlot) cleanSomeSlots(expungeStaleEntry(slotToExpunge), len); }private int expungeStaleEntry(int staleSlot) { Entry[] tab = table;int len = tab.length;tab[staleSlot].value = null; tab[staleSlot] = null; size--; Entry e;int i;for (i = nextIndex(staleSlot, len); (e = tab[i]) != null; i = nextIndex(i, len)) { ThreadLocal k = e.get();if (k == null) { e.value = null; tab[i] = null; size--; } else {int h = k.threadLocalHashCode & (len - 1);if (h != i) { tab[i] = null;while (tab[h] != null) h = nextIndex(h, len); tab[h] = e; } } }return i; }private boolean cleanSomeSlots(int i, int n) {boolean removed = false; Entry[] tab = table;int len = tab.length;do { i = nextIndex(i, len); Entry e = tab[i];if (e != null && e.get() == null) { n = len; removed = true; i = expungeStaleEntry(i); } } while ( (n >>>= 1) != 0);return removed; }private void rehash() { expungeStaleEntries();// Use lower threshold for doubling to avoid hysteresisif (size >= threshold - threshold / 4) resize(); }private void resize() { Entry[] oldTab = table;int oldLen = oldTab.length;int newLen = oldLen * 2; Entry[] newTab = new Entry[newLen];int count = 0;for (int j = 0; j < oldLen; ++j) { Entry e = oldTab[j];if (e != null) { ThreadLocal k = e.get();if (k == null) { e.value = null; // Help the GC} else {int h = k.threadLocalHashCode & (newLen - 1);while (newTab[h] != null) h = nextIndex(h, newLen); newTab[h] = e; count++; } } } setThreshold(newLen); size = count; table = newTab; }private void expungeStaleEntries() { Entry[] tab = table;int len = tab.length;for (int j = 0; j < len; j++) { Entry e = tab[j];if (e != null && e.get() == null) expungeStaleEntry(j); } } } }
このように、同じ接続が使用されますが、それぞれの接続は新しいものであり、同じ接続のコピーです。
それでは、その実装メカニズムは何でしょうか?
1. 各 Thread オブジェクトは内部で ThreadLocalMap を維持します。このような ThreadLocal Map は複数の ThreadLocals を格納できます
/* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ThreadLocal.ThreadLocalMap threadLocals = null;
2。get() メソッドを呼び出すと、次に ThreadLocalMap に移動します。現在のスレッドのオブジェクトが空でない場合は、ThreadLocal の値を取り出します。それ以外の場合、初期化では、initialValue の値を ThreadLocal に設定します。
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t);if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this);if (e != null)return (T)e.value; }return setInitialValue(); }
3. set() メソッドを呼び出すとき、値を ThreadLocal に設定するのが非常に一般的です。
4. 概要: get メソッドを呼び出すと、実際には現在の各スレッドに ThreadLocal が存在します。それぞれの取得または設定は ThreadLocal 上の操作であり、他のスレッドとは独立しています。
5. アプリケーション シナリオ: ThreadLocal は、多くのスレッドが同じオブジェクトを複数回使用する必要があり、オブジェクトが同じ初期化値を持つ必要がある場合に使用するのに最適です。
6. 実際、いくら言っても、ソースコードを見たほうがわかりやすいです。ソース コードを見たい場合は、WeakReference と Map が関係します。これら 2 つは a.Java の弱参照であること、つまり、ラップされた (参照された) 参照は途中で破棄されることを理解する必要があります。 GC オブジェクト、キーとしてのこの threadLocal は破棄される可能性がありますが、定義したクラスがアンロードされない限り、tl の強参照は常にこの ThreadLocal を参照し、gc によって削除されることはありません。 b. ハッシュマップに似ています。
以上がスレッドローカル変数とは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









Javaのクラスロードには、ブートストラップ、拡張機能、およびアプリケーションクラスローダーを備えた階層システムを使用して、クラスの読み込み、リンク、および初期化が含まれます。親の委任モデルは、コアクラスが最初にロードされ、カスタムクラスのLOAに影響を与えることを保証します

この記事では、カフェインとグアバキャッシュを使用してJavaでマルチレベルキャッシュを実装してアプリケーションのパフォーマンスを向上させています。セットアップ、統合、パフォーマンスの利点をカバーし、構成と立ち退きポリシー管理Best Pra

この記事では、キャッシュや怠zyなロードなどの高度な機能を備えたオブジェクトリレーショナルマッピングにJPAを使用することについて説明します。潜在的な落とし穴を強調しながら、パフォーマンスを最適化するためのセットアップ、エンティティマッピング、およびベストプラクティスをカバーしています。[159文字]

この記事では、Javaプロジェクト管理、自動化の構築、依存関係の解像度にMavenとGradleを使用して、アプローチと最適化戦略を比較して説明します。

この記事では、MavenやGradleなどのツールを使用して、適切なバージョン化と依存関係管理を使用して、カスタムJavaライブラリ(JARファイル)の作成と使用について説明します。
