ThreadLocalの原理と使用シーン
5651 ワード
一、ThreadLocal原理
ThreadLocalのset()メソッドを読めば、get()やremove()メソッドもわかりやすいので、set()メソッドを重点的に見てみましょう.
set()メソッド実行プロセスのまとめ:
1.現在のスレッドオブジェクトの取得
2.現在のスレッド・オブジェクトのメンバー変数ThreadLocalMapの取得
3.1 nullではなくset値
3.1.1現在のThreadLocalMapオブジェクトのEntry配列を取得する
3.1.2 ThreadLocalオブジェクトのi値の取得
3.1.3 Entry配列を遍歴し、ThreadLocalオブジェクトのi値から判断し、ThreadLocalオブジェクトが既に配列中にある場合、値を更新し、終了する
3.1.4配列は存在しない、key-value形式で:ThreadLocalオブジェクトと値valueを結合して配列に入れる
3.2 null、現在のスレッドのメンバー変数ThreadLocalMapを作成する
3.2.1 new 1つのEntry配列、初期容量はINITIAL_CAPACITY=16
3.2.2 Entry配列に格納されている位置i:ThreadLocalのthreadLocalHashCodeと15のビット演算を算出し、結果は型取りと同じである.
3.2.3 Entry配列を入れる
ソース分析は以下の通りです.
上記のソースコードに基づいて以下をまとめます.
1つのThreadオブジェクトに複数のThreadLocalオブジェクトがスレッドのローカルメモリに値を格納し、1つのThreadLocalオブジェクトが複数のスレッドのローカルメモリに値を格納します.だからThreadとThreadLocalは簡単に多対多関係と理解できる.(スレッドのローカルメモリはスレッドのワークメモリとも呼ばれ、JMMメモリモデル定義の概念)
ThreadLocalの本質はツールクラスであり、set()、get()、remove()などの方法を提供し、スレッドのローカルメモリの値の操作を提供する.Threadのメンバー変数ThreadLocalMapはスレッドのローカルメモリデータ格納を実現し(ポイント:メンバー変数はローカルメモリオブジェクトの格納を実現する)、ThreadLocalMapはThreadLocalに定義された静的内部クラスである.
ThreadLocalMapはEntryタイプの配列を維持し、EntryはThreadLocalMapに定義された静的内部クラスであり、EntryはObjectタイプのメンバー変数valueを使用して値を格納し、Entryの構造関数は本ThreadLocalオブジェクトとスレッド値valueをkey-value形式でバインドします.ThreadLocalの対応するEntry[]配列の下付きiは、ThreadLocalのhash値がfinalであるため、唯一変わらない.
二、ThreadLocal使用シーン
SynchronizedとThreadLocalは、マルチスレッド同時データアクセスを解決するために使用されますが、Synchronizedはスレッド間のデータ共有に使用され、ThreadLocalはスレッド間のデータ分離に使用されます.だから、シーンを使うには、この変数自体が共有されるべきかどうかによって!
ThreadLocalでは、データベース接続、セッション管理などを解決するためにシーンをよく使用します.springの管理を参照できます.例:1つの変数はメンバー変数(マルチスレッド共有)ですが、本質的にスレッドがプライベートであるべきで、ThreadLocalで共有メンバー変数copyをスレッドプライベート変数に1部使用できます.次のようにDemo:
ThreadLocalのset()メソッドを読めば、get()やremove()メソッドもわかりやすいので、set()メソッドを重点的に見てみましょう.
set()メソッド実行プロセスのまとめ:
1.現在のスレッドオブジェクトの取得
2.現在のスレッド・オブジェクトのメンバー変数ThreadLocalMapの取得
3.1 nullではなくset値
3.1.1現在のThreadLocalMapオブジェクトのEntry配列を取得する
3.1.2 ThreadLocalオブジェクトのi値の取得
3.1.3 Entry配列を遍歴し、ThreadLocalオブジェクトのi値から判断し、ThreadLocalオブジェクトが既に配列中にある場合、値を更新し、終了する
3.1.4配列は存在しない、key-value形式で:ThreadLocalオブジェクトと値valueを結合して配列に入れる
3.2 null、現在のスレッドのメンバー変数ThreadLocalMapを作成する
3.2.1 new 1つのEntry配列、初期容量はINITIAL_CAPACITY=16
3.2.2 Entry配列に格納されている位置i:ThreadLocalのthreadLocalHashCodeと15のビット演算を算出し、結果は型取りと同じである.
3.2.3 Entry配列を入れる
ソース分析は以下の通りです.
public class Thread implements Runnable {
// ThreadLocalMap
ThreadLocal.ThreadLocalMap threadLocals = null;
}
public class ThreadLocal {
private final int threadLocalHashCode = nextHashCode();
public T get() {}
public void remove() {}
public void set(T value) {
Thread t = Thread.currentThread();//
ThreadLocal.ThreadLocalMap map = getMap(t);// ThreadLocalMap
if (map != null)
map.set(this, value);// null,set
else
createMap(t, value);// null, ThreadLocalMap
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocal.ThreadLocalMap(this, firstValue);// ThreadLocalMap
}
static class ThreadLocalMap {
private static final int INITIAL_CAPACITY = 16;
static class Entry extends WeakReference> {
//
Object value;
// key-value , ThreadLocal Object 。 ThreadLocal Thread Object。
Entry(ThreadLocal> k, Object v) {
super(k);
value = v;
}
}
//ThreadLocalMap Entry table
private ThreadLocal.ThreadLocalMap.Entry[] table;
ThreadLocalMap(ThreadLocal> firstKey, Object firstValue) {
table = new ThreadLocal.ThreadLocalMap.Entry[INITIAL_CAPACITY];//new Entry , INITIAL_CAPACITY=16
/**
* table :ThreadLocal threadLocalHashCode 15 , 。
* ThreadLocal ,threadLocalHashCode final , ThreadLocal i ,
* ThreadLocal Thread Object
*/
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new ThreadLocal.ThreadLocalMap.Entry(firstKey, firstValue);// Entry
size = 1;
setThreshold(INITIAL_CAPACITY);
}
private void set(ThreadLocal> key, Object value) {
ThreadLocal.ThreadLocalMap.Entry[] tab = table;// ThreadLocalMap Entry
int len = tab.length;
int i = key.threadLocalHashCode & (len - 1);//ThreadLocal i
// Entry
for (ThreadLocal.ThreadLocalMap.Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal> k = e.get();
//ThreadLocal , ,
if (k == key) {
e.value = value;
return;
}
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
// , key-value : ThreadLocal value
tab[i] = new ThreadLocal.ThreadLocalMap.Entry(key, value);
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
}
}
上記のソースコードに基づいて以下をまとめます.
1つのThreadオブジェクトに複数のThreadLocalオブジェクトがスレッドのローカルメモリに値を格納し、1つのThreadLocalオブジェクトが複数のスレッドのローカルメモリに値を格納します.だからThreadとThreadLocalは簡単に多対多関係と理解できる.(スレッドのローカルメモリはスレッドのワークメモリとも呼ばれ、JMMメモリモデル定義の概念)
ThreadLocalの本質はツールクラスであり、set()、get()、remove()などの方法を提供し、スレッドのローカルメモリの値の操作を提供する.Threadのメンバー変数ThreadLocalMapはスレッドのローカルメモリデータ格納を実現し(ポイント:メンバー変数はローカルメモリオブジェクトの格納を実現する)、ThreadLocalMapはThreadLocalに定義された静的内部クラスである.
ThreadLocalMapはEntryタイプの配列を維持し、EntryはThreadLocalMapに定義された静的内部クラスであり、EntryはObjectタイプのメンバー変数valueを使用して値を格納し、Entryの構造関数は本ThreadLocalオブジェクトとスレッド値valueをkey-value形式でバインドします.ThreadLocalの対応するEntry[]配列の下付きiは、ThreadLocalのhash値がfinalであるため、唯一変わらない.
二、ThreadLocal使用シーン
SynchronizedとThreadLocalは、マルチスレッド同時データアクセスを解決するために使用されますが、Synchronizedはスレッド間のデータ共有に使用され、ThreadLocalはスレッド間のデータ分離に使用されます.だから、シーンを使うには、この変数自体が共有されるべきかどうかによって!
ThreadLocalでは、データベース接続、セッション管理などを解決するためにシーンをよく使用します.springの管理を参照できます.例:1つの変数はメンバー変数(マルチスレッド共有)ですが、本質的にスレッドがプライベートであるべきで、ThreadLocalで共有メンバー変数copyをスレッドプライベート変数に1部使用できます.次のようにDemo:
/**
* : MyThreadLocal ,sendMessage() , sendMessage() ?
* : connection 。 ThreadLocal
**/
public class MyThreadLocal {
// ,
private Connection connection;
public static ThreadLocal threadLocal = new ThreadLocal();
public void sendMessage() throws SQLException {
//Statement statement = connection.createStatement();
Statement statement = getConnection().createStatement();
//...
}
public static Connection getConnection() {
Connection conn = threadLocal.get();// value
if (conn == null) {
Connection conn = ConnectionManager.getConnection();
threadLocal.set(conn);
return conn;
} else {
return conn;
}
}
}