この記事の内容は、Java マルチスレッドでの ThreadLocal の使用に関するものです。必要な方は参考にしていただければ幸いです。
マルチスレッド環境では、synchronized
メソッドを使用してHashMap# にアクセスするなど、非スレッドセーフ変数にアクセスするときにスレッド同期を実行する必要があります。 ## 実例。ただし、同期アクセスは同時実行性を低下させ、システムのパフォーマンスに影響を与えます。このとき、各スレッドに独立した変数を割り当てると、非スレッド セーフな変数を非同期的に使用できるようになり、そのような変数をスレッド ローカル変数と呼びます。
Javaは言語レベルのスレッドローカル変数を提供していませんが、今回の主役である
ThreadLocalクラスのクラスライブラリ内でスレッドローカル変数の機能を提供しています。
ThreadLocal の使用法
##ThreadLocal の Java8 バージョンには、上の図に示す 4 つがあります。 2 つのパブリック メソッドと 1 つの保護されたメソッドがあります。最初のメソッドは初期値 (デフォルトでは null) を返すために使用されます。 2 番目の静的メソッド withInitial(Supplier extends S>supplier) は Java8 バージョンで新しく追加されたもので、次の 3 つのインスタンス メソッドは非常に単純です。
Java8 より前では、ThreadLocal を使用するときに初期値を設定する場合は、ThreadLocal クラスを継承し、保護された T のinitialValue() メソッドをオーバーライドする必要があります。例:
ThreadLocalthreadLocal = new ThreadLocal () { @Override protected Integer initialValue() { return 0; } };
ThreadLocalthreadLocal = ThreadLocal.withInitial(() -> 0); System.out.println(threadLocal.get()); threadLocal.set(16); System.out.println(threadLocal.get()); threadLocal.remove(); System.out.println(threadLocal.get()); // 同一个线程的输出 0 16 0 Process finished with exit code 0
ThreadLocal の原理
では、ThreadLocal はスレッドローカル変数の機能をどのように実装するのでしょうか?実際、ThreadLocal の基本原理はそれほど複雑ではありません。 ThreadLocal は内部で静的クラス ThreadLocalMap を定義します。ThreadLocalMap のキーは ThreadLocal オブジェクトです。ただし、この ThreadLocalMap は ThreadLocal クラスに保持されます。 ThreadLocal のソース コードの一部を見てみましょう:
// ThreadLocal的set方法 public void set(T value) { // 获取当前线程对象 Thread t = Thread.currentThread(); // 获取Map ThreadLocalMap map = getMap(t); if (map != null) // 设置值 map.set(this, value); else // 初始化Map createMap(t, value); } // ThreadLocal的createMap方法 void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); } // Thread类定义的实例域 /* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null;
static class Entry extends WeakReference> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal> k, Object v) { super(k); value = v; } }
// ThreadLocalMap的set方法 private void set(ThreadLocal> key, Object value) { Entry[] tab = table; int len = tab.length; // 计算在Entry[]中的索引,每个ThreadLocal对象都有一个hash值threadLocalHashCode,每初始化一个ThreadLocal对象,hash值就增加一个固定的大小0x61c88647 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 static int nextIndex(int i, int len) { return ((i + 1 ThreadLocalMap が Entry[] 配列をリングとして扱っていることがわかります。計算したインデックスの位置を起点として、インデックスに既にデータがある場合はKeyが同じかどうかを判定し、同じであれば値を更新します。それ以外の場合は、空の位置が見つかるまで待って、そこに値を入れます。値を取得する場合も同様で、計算されたインデックスの位置から開始して、キーが同じであるかどうかを 1 つずつチェックします。ハッシュの衝突が多い場合、パフォーマンスがあまり良くない可能性があります。ThreadLocal のアプリケーション
##ThreadLocal のアプリケーションは非常に広範囲に渡ります。たとえば、Java エンジニアは次のようになります。 ThreadLocal は Spring フレームワークで非スレッドセーフのステートフル オブジェクトをカプセル化するために使用されるため、ほとんどの Bean をシングルトン スコープとして宣言できます。マルチスレッド コードを記述するときは、非スレッド セーフ ステートフル オブジェクトに同期的にアクセスする方が良いのか、それとも ThreadLocal を使用して非スレッド セーフ ステートフル オブジェクトをカプセル化する方が良いのかを考えることもできます。
以上がJava マルチスレッドでの ThreadLocal の使用の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。