JDK 1.8同時進行のThreadLocalソース解析
9184 ワード
本文の目的はThreadLocalのソースコードを分析することです。ThreadLocalの使い方について、参考資料を読んでください。
ThreadLocal.ThreadLocal Map
各スレッドオブジェクトには、ThreadLocal Mapタイプの変数があります。ThreadLocal MapはThreadLocalの内部クラスであり、線形探知法に基づく分散リストで実現される。各スレッドオブジェクトは、Mapに複数のThreadLocalオブジェクトをキーとするキーペアを追加することができ、各キーに対応する値は一意です。したがって、一つのThreadLocalオブジェクトによって設定された値は、スレッドごとに一意であり、互いに独立している。唯一の理由はキーの唯一性であり、個々のスレッドには独自のThreadLocarMap内部変数があり、それはすべてスレッドに帰属しているからである。
したがって、
ThreadLocalのset方法
現在のスレッドのThreadLocal Mapオブジェクトにキーペアを追加します。キーはThreadLocalオブジェクトで、設定されたvalueオブジェクトの値です。
スレッドでgetメソッドを呼び出した場合、以前にset方式でこのThreadLocalキーに値を追加した場合、設定した値を返します。そうでなければデフォルトの初期値nullに戻ります。
通常、ThreadLocalオブジェクトを新規作成する場合、共有の初期値を設定するために、匿名の内部クラスでこの方法を書き換えることができる。詳細は参考資料1による。のいくつかのデータはスレッドを作用領域とし、異なるスレッドは異なるデータのコピーを有する。Androidメッセージシステムでは、スレッドごとに独自のLooperが必要であり、ThreadLocalを通じてLooperのスレッドへのアクセスが簡単に行えます。 複雑な論理でのオブジェクト転送。例えば、タスクが複雑な場合は、関数コールスタックがより深いですが、また、モニターがスレッド全体を通してプロセスを実行する必要があります。ThreadLocalを使って、モニターをスレッド内のグローバルオブジェクトにすることができます。 参考資料 ThreadLocalの設計理念と役割 JavaにおけるThreadLocalとInheitable ThreadLocal ThreadLocalの原理解析(2):ThreadLocal Mapソース解析 Javaにおける強、軟、弱、虚引用
ThreadLocal.ThreadLocal Map
各スレッドオブジェクトには、ThreadLocal Mapタイプの変数があります。ThreadLocal MapはThreadLocalの内部クラスであり、線形探知法に基づく分散リストで実現される。各スレッドオブジェクトは、Mapに複数のThreadLocalオブジェクトをキーとするキーペアを追加することができ、各キーに対応する値は一意です。したがって、一つのThreadLocalオブジェクトによって設定された値は、スレッドごとに一意であり、互いに独立している。唯一の理由はキーの唯一性であり、個々のスレッドには独自のThreadLocarMap内部変数があり、それはすべてスレッドに帰属しているからである。
// java.lang.ThreadLocal.ThreadLocalMap
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);
}
興味深いことに、その元素は弱い引用であり、弱い引用によって関連された対象は次のゴミ収集が発生する前に生存するしかない。ゴミ収集器が作動すると、現在のメモリが十分かどうかにかかわらず、参照対象のみを回収します。このため、あるスレッドがすでに実行済みであれば、ここに引用があっても回収できないことはなく、このキーは回収後にnullになります。したがって、
ThreadLocalMap
のset
方法では、rehash
,rehash
を呼び出すことができ、これらはすでにnullになっている弱い参照を整理し、後の部分Entryに対してハッシュハッシュハッシュハッシュハッシュハッシュハッシュハッシュを再実行し、最後に拡張するかどうかを判断する。おすすめの参考資料3)static class Entry extends WeakReference> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal> k, Object v) {
super(k);
value = v;
}
}
ThreadLocalコンストラクタpublic ThreadLocal() {
}
コンストラクタは空ですThreadLocalのset方法
現在のスレッドのThreadLocal Mapオブジェクトにキーペアを追加します。キーはThreadLocalオブジェクトで、設定されたvalueオブジェクトの値です。
public void set(T value) {
//
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
// set get , map , ThreadLocal
if (map != null)
map.set(this, value);
// set get , ThreadLocalMap
// , ThreadLocal
else
createMap(t, value);
}
// Thread t ThreadLocalMap , null
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
ThreadLocalのget方法スレッドでgetメソッドを呼び出した場合、以前にset方式でこのThreadLocalキーに値を追加した場合、設定した値を返します。そうでなければデフォルトの初期値nullに戻ります。
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
// set get , ,
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
// set get , , ,
return setInitialValue();
}
private T setInitialValue() {
//
T value = initialValue();
// set
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
ThreadLocalのinitial Value通常、ThreadLocalオブジェクトを新規作成する場合、共有の初期値を設定するために、匿名の内部クラスでこの方法を書き換えることができる。詳細は参考資料1による。
// , ThreadLocal
protected T initialValue() {
return null;
}
Inheitable ThreadLocalInheritableThreadLocal
を使用して、親スレッドがnewスレッドの前に保持されているInheritableThreadLocal
変数のオブジェクト値をサブスレッドで取得することができる。public class Main {
private static InheritableThreadLocal local =
new InheritableThreadLocal<>();
public static void main(String[] args) throws InterruptedException {
local.set(1001);
new Thread(() -> {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() +
":" + local.get());
}).start();
Thread.sleep(1000);
local.set(2002);
System.out.println(Thread.currentThread().getName() +
":" + local.get());
}
}
/* :
main:2002
Thread-0:1001
*/
これは、スレッドごとに作成時に、親スレッドオブジェクトのinheitable ThreadLocars属性がコピーされるからです。親スレッドのinherityable ThreadLocarsオブジェクトが空でない場合は、子スレッドにコピーし、対象参照(クローンではない)をコピーした後、親スレッドがinherityable ThreadLocal変数setに新しい値は子スレッドに影響しませんが、親スレッド修正値オブジェクトが山にあるフィールドであれば、子スレッドの値も変化します。public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null, true);
}
// inheritThreadLocals = true
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
...
//
Thread parent = currentThread();
...
// inheritableThreadLocals , 。
// , inheritableThreadLocal set
// , ,
//
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
...
}
ThreadLocal使用シーン