6のJavaの並行処理シリーズ:ThreadLocalのの深い理解

入門

かかわらず、実際のプロジェクトの戦闘やインタビューの、ThreadLocal話題を中心に、ソースとみんなの観点から、本論文では、次の議論を開いていないThreadLocal謎を。

  • ThreadLocal何ですか?それは行うことができますか?
  • ThreadLocalソースコード解析
  • 概要

まず、ThreadLocal何がありますか?それは行うことができますか?

ThreadLocal 他のスレッドと共有されていない変数がスレッドに排他的であることを意味し、スレッドローカル変数であり、それはマルチスレッド共有変数の問題を解決していません。

だから、ThreadLocal別のスレッド同期機構を、スレッド同期メカニズムは、複数のスレッドが同じ変数を共有しており、ThreadLocalすべてのスレッドが変数の個別のコピーを作成するため、各スレッドではなく、彼らが持っているものは独立変数のコピーを変更することができ、ありますそれはコピーを、対応する他のスレッドに影響を与えます。言うことができるThreadLocal、マルチスレッド環境変数は代替解決策のアイデアを提供しています。

ThreadLocalアイデアは、各スレッドは、この変数の独自のAのコピーにアクセスできるように、時間のためのスペースを使用することで、変数の値は、同じスレッドのパス内の複数のコンポーネント間でいくつかのパブリック関数や変数の複雑さを軽減、互いに干渉しません。

ここに画像を挿入説明


第二に、ThreadLocalソースコード解析

図1に示すように、ThreadLocalMap構文解析
ThreadLocalの中で定義されThreadLocalMap、内部クラスThreadLocalMap実際の使用をEntry達成するためにkey-value次のように、ストレージ。

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;
            }
        }
        ...
}

ThreadLocalMapキースレッド分離機構は、上記のコードから分かることは、EntryあるkeyことをThreadLocalしながら、valueその値。それと同時に、Entryまた、継承されたWeakReferenceように、Entry対応するkeyThreadLocal弱参照として参考例)。

私たちは、主にコアを見てgetEntry()set(ThreadLocal> key, Object value)方法

private Entry getEntry(ThreadLocal<?> key) {
            int i = key.threadLocalHashCode & (table.length - 1);
            Entry e = table[i];
            if (e != null && e.get() == key)
                return e;
            else
                return getEntryAfterMiss(key, i, e);
        }
 private void set(ThreadLocal<?> key, Object value) {

            // We don't use a fast path as with get() because it is at
            // least as common to use set() to create new entries as
            // it is to replace existing ones, in which case, a fast
            // path would fail more often than not.

            Entry[] tab = table;
            int len = tab.length;
            // 根据 ThreadLocal 的散列值,查找对应元素在数组中的位置
            int i = key.threadLocalHashCode & (len-1);

			// 采用“线性探测法”,寻找合适位置
            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal<?> k = e.get();
				// 若key 存在,直接覆盖
                if (k == key) {
                    e.value = value;
                    return;
                }
				// key == null,但是存在值(因为此处的e != null),说明之前的ThreadLocal对象已经被回收了
                if (k == null) {
                	// 用新元素替换陈旧的元素
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }
			//创建新元素
            tab[i] = new Entry(key, value);
            int sz = ++size;
            // 如果没有清理陈旧的 Entry 并且数组中的元素大于了阈值,则进行 rehash
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }

図2は、コア分析法
(1)(GET)
現在のスレッドの値は、このスレッドローカルでのコピーを返します

public T get() {
		//获取当前线程
        Thread t = Thread.currentThread();
        //获取当前线程的成员变量 threadLocalMap
        ThreadLocalMap map = getMap(t);
        if (map != null) {
        	// 从当前线程的ThreadLocalMap获取相对应的Entry
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                // 获取目标值
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

まず、現在のスレッドに対応するメンバ変数を介して取得ThreadLocalMapした後、ThreadLocalMap現在の取得ThreadLocalEntryエントリは、取得したことにより、前回の取得対象をresult

(2)セット(T値)
指定された値のスレッドローカル変数のコピーに、現在のスレッドのためにこの値の。

public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

対応する現在のスレッドを取得ThreadLocalMap空でない場合、呼び出し、メソッドを、キーが存在している、とされていない場合、その呼新しいを作成する方法を。ThreadLocalMapset()ThreadLocalcreateMap()

void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

(3)はinitialValue()
現在のスレッドがこのスレッドローカル変数の初期値で返します。

protected T initialValue() {
        return null;
    }

このメソッドは次のように定義されprotectedレベルと戻りnull我々が使用するので、サブクラスへの必要性がその機能を実行するThreadLocal。この方法時間をオーバーライドする必要があり、一般的に。このメソッドは、呼び出し、最初の呼び出しを示していないget()か、set()方法、およびは、一度だけ行ったときに実行されます。

(4)削除()
このスレッドローカル変数に対する現在のスレッドの値を削除します。

 public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }

第三に、要約

複数のスレッドがこの変数の初期値のコピーを得るために、要件を共有変数を取得するための1、。この変数を格納するために、各スレッドのコピー、この変数を変更するには、変数自体のコピーには影響を与えません。複数のスレッドのために異なるシーンの操作従属変数値を完了します。例えば:

  • 複数のデータソースを切り替えます
  • 春宣言的トランザクション

図2は、されThreadLocalprivate static、そうThreadLocalしようとすると、糸自体と一緒に回復します。

公開された86元の記事 ウォン称賛45 ビュー80000 +

おすすめ

転載: blog.csdn.net/Diamond_Tao/article/details/103865434