入門
かかわらず、実際のプロジェクトの戦闘やインタビューの、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
対応するkey
(ThreadLocal
弱参照として参考例)。
私たちは、主にコアを見て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
現在の取得ThreadLocal
のEntry
エントリは、取得したことにより、前回の取得対象を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
空でない場合、呼び出し、メソッドを、キーが存在している、とされていない場合、その呼新しいを作成する方法を。ThreadLocalMap
set()
ThreadLocal
createMap()
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は、されThreadLocal
てprivate static
、そうThreadLocal
しようとすると、糸自体と一緒に回復します。