NettyのFastThreadLocalソースのトレース
10217 ワード
前期準備ゼロ
0 FBI WARNING
文章はとてもくどくて回りくどい.
バージョン1
JDKバージョン:OpenJDK 11.0.1
IDE : idea 2018.3
Nettyバージョン:netty-all 4.1.34.Final
2 FastThreadLocalの概要
FastThreadLocalはNettyで実現される高性能ThreadLocalツールであり、機能的にはThreadLocalと差は少ないが、jdkが持参したThreadLocalよりはるかに性能的に高い.
3 Demo
FastThreadLocalの作成
Demoの作成コードに戻ります.
FastThreadLocalのコンストラクタのトレース:
FastThreadLocalの作成は、IDとして一意のint値を取得するだけで、他の操作はありません.
二InternalThreadLocalMap
InternalThreadLocalMapはFastThreadLocalの下位層で本当に機能するThreadLocalクラスであり,多くの静的方法を提供している.
1オブジェクトの取得
最も重要なのはInternalThreadLocalMapのget()メソッドです.
まずfastGet()を見てみましょう.
slowGet():
実際にFastThreadLocalにとって、本当に役に立つのはInternalThreadLocalMapオブジェクトであることがわかります.
通常のスレッドでは,このオブジェクト自体はjdkのオリジナルサポートがないため,ThreadLocalオブジェクトにしかアタッチできない.
ただし、UnpaddedInternalThreadLocalMapのslowThreadLocalMap自体は静的ThreadLocalオブジェクトであるため、異なるスレッドが実際に呼び出されるのは同じオブジェクトであるが、取得されたInternalThreadLocalMapは同じではない.同じスレッドで複数のFastThreadLocalオブジェクトを作成すると、同じInternalThreadLocalMapが取得されます.
2 set
InternalThreadLocalMapの最下位ストレージはObject配列であり、setIndexedVariable(...)メソッドで格納されます.
3 get
InternalThreadLocalMapで値を取得する方法は、indexedVariable(...)を使用します.
4 remove
InternalThreadLocalMapで値を削除する方法はindexedVariable(...)で行います.
InternalThreadLocalMapには、自身を消去するための静的remove()メソッドもあります.
コードは比較的簡単で、あまり分析しません.
にメモリエレメント
Demoの格納要素のコードに戻ります.
追跡get(...)メソッド:
三取得要素
Demoで取得した要素のコードに戻ります.
トレースset(...)メソッド:
3要素の除去
Demoから要素を除去するコードに戻ります.
トレースremove(...)メソッド:
クアッドメモリ管理
実際の開発環境では、スレッドがこのFastThreadLocalを使用し、スレッドが完了した後にgcによって回収されたが、このFastThreadLocalの値が回収されていない場合があるかもしれない.
FastThreadLocalでは、メモリの漏洩を防ぐ方法registerCleaner(...):
メーデーの小言
FastThreadLocalはjdkのオリジナルThreadLocalと比較して、性能の優位性は主に以下のいくつかの方面に現れます:
本文は個人の学習ノートのみで、誤りや表現がはっきりしないところがある可能性があります.
0 FBI WARNING
文章はとてもくどくて回りくどい.
バージョン1
JDKバージョン:OpenJDK 11.0.1
IDE : idea 2018.3
Nettyバージョン:netty-all 4.1.34.Final
2 FastThreadLocalの概要
FastThreadLocalはNettyで実現される高性能ThreadLocalツールであり、機能的にはThreadLocalと差は少ないが、jdkが持参したThreadLocalよりはるかに性能的に高い.
3 Demo
import io.netty.util.concurrent.FastThreadLocal;
public class FastThreadLocalDemo {
public static void main(String[] args) {
// FastThreadLocal
FastThreadLocal tl = new FastThreadLocal<>();
//FastThreadLocal
long setBegin = System.nanoTime();
tl.set("test");
long setAfter = System.nanoTime();
System.out.println("get : " + (setAfter - setBegin));
//FastThreadLocal
long getBegin = System.nanoTime();
String fastGet = tl.get();
long getAfter = System.nanoTime();
System.out.println("get : " + (getAfter - getBegin));
//FastThreadLocal
long removeBegin = System.nanoTime();
tl.remove();
long removeAfter = System.nanoTime();
System.out.println("remove : " + (removeAfter - removeBegin));
}
}
FastThreadLocalの作成
Demoの作成コードに戻ります.
FastThreadLocal tl = new FastThreadLocal<>();
FastThreadLocalのコンストラクタのトレース:
//step 1
//FastThreadLocal.class
public FastThreadLocal() {
//index int
index = InternalThreadLocalMap.nextVariableIndex();
}
//step 2
//InternalThreadLocalMap.class
public static int nextVariableIndex() {
//nextIndex UnpaddedInternalThreadLocalMap AtomicInteger
//UnpaddedInternalThreadLocalMap InternalThreadLocalMap
// int ,
int index = nextIndex.getAndIncrement();
if (index < 0) {
nextIndex.decrementAndGet();
throw new IllegalStateException("too many thread-local indexed variables");
}
return index;
}
FastThreadLocalの作成は、IDとして一意のint値を取得するだけで、他の操作はありません.
二InternalThreadLocalMap
InternalThreadLocalMapはFastThreadLocalの下位層で本当に機能するThreadLocalクラスであり,多くの静的方法を提供している.
1オブジェクトの取得
最も重要なのはInternalThreadLocalMapのget()メソッドです.
//InternalThreadLocalMap.class
public static InternalThreadLocalMap get() {
//
Thread thread = Thread.currentThread();
//
if (thread instanceof FastThreadLocalThread) {
// Netty FastThreadLocal
return fastGet((FastThreadLocalThread) thread);
} else {
// FastThreadLocal, FastThreadLocalThread
return slowGet();
}
}
まずfastGet()を見てみましょう.
//InternalThreadLocalMap.class
private static InternalThreadLocalMap fastGet(FastThreadLocalThread thread) {
// FastThreadLocalThread threadLocalMap
InternalThreadLocalMap threadLocalMap = thread.threadLocalMap();
//
if (threadLocalMap == null) {
thread.setThreadLocalMap(threadLocalMap = new InternalThreadLocalMap());
}
return threadLocalMap;
}
slowGet():
//InternalThreadLocalMap.class
private static InternalThreadLocalMap slowGet() {
// UnpaddedInternalThreadLocalMap slowThreadLocalMap
//slowThreadLocalMap ThreadLocal , InternalThreadLocalMap
ThreadLocal slowThreadLocalMap = UnpaddedInternalThreadLocalMap.slowThreadLocalMap;
// InternalThreadLocalMap
InternalThreadLocalMap ret = slowThreadLocalMap.get();
//
if (ret == null) {
ret = new InternalThreadLocalMap();
slowThreadLocalMap.set(ret);
}
return ret;
}
実際にFastThreadLocalにとって、本当に役に立つのはInternalThreadLocalMapオブジェクトであることがわかります.
通常のスレッドでは,このオブジェクト自体はjdkのオリジナルサポートがないため,ThreadLocalオブジェクトにしかアタッチできない.
ただし、UnpaddedInternalThreadLocalMapのslowThreadLocalMap自体は静的ThreadLocalオブジェクトであるため、異なるスレッドが実際に呼び出されるのは同じオブジェクトであるが、取得されたInternalThreadLocalMapは同じではない.同じスレッドで複数のFastThreadLocalオブジェクトを作成すると、同じInternalThreadLocalMapが取得されます.
2 set
InternalThreadLocalMapの最下位ストレージはObject配列であり、setIndexedVariable(...)メソッドで格納されます.
//InternalThreadLocalMap.class
public boolean setIndexedVariable(int index, Object value) {
//indexedVariables UnpaddedInternalThreadLocalMap Object
Object[] lookup = indexedVariables;
//
//index FastThreadLocal ,
if (index < lookup.length) {
//
Object oldValue = lookup[index];
//
lookup[index] = value;
//UNSET Object , lookup
// oldValue UNSET,
// , , false
return oldValue == UNSET;
} else {
//
expandIndexedVariableTableAndSet(index, value);
return true;
}
}
3 get
InternalThreadLocalMapで値を取得する方法は、indexedVariable(...)を使用します.
//InternalThreadLocalMap.class
public Object indexedVariable(int index) {
// index
Object[] lookup = indexedVariables;
return index < lookup.length? lookup[index] : UNSET;
}
4 remove
InternalThreadLocalMapで値を削除する方法はindexedVariable(...)で行います.
//InternalThreadLocalMap.class
public Object removeIndexedVariable(int index) {
//
Object[] lookup = indexedVariables;
if (index < lookup.length) {
Object v = lookup[index];
// UNSET
lookup[index] = UNSET;
return v;
} else {
return UNSET;
}
}
InternalThreadLocalMapには、自身を消去するための静的remove()メソッドもあります.
//InternalThreadLocalMap.class
public static void remove() {
Thread thread = Thread.currentThread();
if (thread instanceof FastThreadLocalThread) {
((FastThreadLocalThread) thread).setThreadLocalMap(null);
} else {
slowThreadLocalMap.remove();
}
}
コードは比較的簡単で、あまり分析しません.
にメモリエレメント
Demoの格納要素のコードに戻ります.
tl.set("test");
追跡get(...)メソッド:
//step 1
//FastThreadLocal.class
public final void set(V value) {
// value UNSET
if (value != InternalThreadLocalMap.UNSET) {
// InternalThreadLocalMap
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
//setKnownNotUnset(...) value threadLocalMap
if (setKnownNotUnset(threadLocalMap, value)) {
// gc
registerCleaner(threadLocalMap);
}
} else {
remove();
}
}
//step 2
//FastThreadLocal.class
private boolean setKnownNotUnset(InternalThreadLocalMap threadLocalMap, V value) {
// setIndexedVariable(...) value, InternalThreadLocalMap
if (threadLocalMap.setIndexedVariable(index, value)) {
//addToVariablesToRemove(...) FastThreadLocal threadLocalMap
// FastThreadLocal
addToVariablesToRemove(threadLocalMap, this);
return true;
}
return false;
}
三取得要素
Demoで取得した要素のコードに戻ります.
String fastGet = tl.get();
トレースset(...)メソッド:
//FastThreadLocal.class
public final V get() {
// InternalThreadLocalMap
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
// InternalThreadLocalMap
Object v = threadLocalMap.indexedVariable(index);
// ,
if (v != InternalThreadLocalMap.UNSET) {
return (V) v;
}
// ,initialize(...) null
V value = initialize(threadLocalMap);
//gc
registerCleaner(threadLocalMap);
// null
return value;
}
3要素の除去
Demoから要素を除去するコードに戻ります.
String fastGet = tl.get();
トレースremove(...)メソッド:
//step 1
//FastThreadLocal.class
public final void remove() {
//InternalThreadLocalMap getIfSet() InternalThreadLocalMap
remove(InternalThreadLocalMap.getIfSet());
}
//step 2
//FastThreadLocal.class
public final void remove(InternalThreadLocalMap threadLocalMap) {
//
if (threadLocalMap == null) {
return;
}
//
Object v = threadLocalMap.removeIndexedVariable(index);
// threadLocalMap FastThreadLocal
removeFromVariablesToRemove(threadLocalMap, this);
if (v != InternalThreadLocalMap.UNSET) {
try {
// , ,
onRemoval((V) v);
} catch (Exception e) {
PlatformDependent.throwException(e);
}
}
}
クアッドメモリ管理
実際の開発環境では、スレッドがこのFastThreadLocalを使用し、スレッドが完了した後にgcによって回収されたが、このFastThreadLocalの値が回収されていない場合があるかもしれない.
FastThreadLocalでは、メモリの漏洩を防ぐ方法registerCleaner(...):
//FastThreadLocal.class
private void registerCleaner(final InternalThreadLocalMap threadLocalMap) {
Thread current = Thread.currentThread();
// FastThreadLocalThread , index ,
if (FastThreadLocalThread.willCleanupFastThreadLocals(current) || threadLocalMap.isCleanerFlagSet(index)) {
return;
}
// index
threadLocalMap.setCleanerFlag(index);
// ,
// , Netty , 4.1.34
// , , , TODO
// ObjectCleaner.register(current, new Runnable() {
// @Override
// public void run() {
// remove(threadLocalMap);
// }
// });
}
メーデーの小言
FastThreadLocalはjdkのオリジナルThreadLocalと比較して、性能の優位性は主に以下のいくつかの方面に現れます:
1、Netty , , FastThreadLocal
2、FastThreadLocal ThreadLocal Hash , , 、
3、ThreadLocal FastThreadLocal ,
4、FastThreadLocal (static) ,
本文は個人の学習ノートのみで、誤りや表現がはっきりしないところがある可能性があります.