ThreadLocalの使い方
4817 ワード
ThreadLocalの役割:
同じスレッドにインスタンスを共有させ、異なるスレッドはそれぞれのインスタンスを使用し、互いに影響しません.
ThreadLocalの本格的な応用解釈:
各スレッドには独自の変数があり、Threadが終了しない限り、いつでも内部のThreadLocalMapを取り出し、ThreadLocal自身と組み合わせることで、Mapに格納されている変数を手に入れることができます.
どうしてこんなことになったの?メソッドチェーンで同じパラメータを渡す手間を解決しました!
適用シーン:
1つのスレッドが実行されており、多くのクラスの異なるメソッドを実行する必要があります.これらのメソッドは変数を使用しています.
では、この変数をどんどん後ろに伝えなければなりません.面倒です.
どのようにしてThreadのライフサイクル全体でこの変数を使用できるのか、ThreadLocalMapを使用して保存します.
各Threadには属性変数があります.
ThreadLocal.ThreadLocalMap threadLocals
ThreadLocalでは、内部クラス(Mapとして)が定義されています.
ThreadLocalMap map
このMapは特殊です.
key - ThreadLocal
value - 私たちが伝える変数
ThreadクラスのこのMapはどのように初期化されていますか?
ThreadLocalオブジェクトを作成し、getメソッドを呼び出して変数を取得すると、Threadから取得したMapが空の場合、
新しいMapが作成され、ThreadのthreadLocalsに参照が割り当てられます.
こうして、TheadにはMapの引用がある.
スレッドがまだ実行されている限り、currentThreadで独自のThreadLocalMapを得ることができます.
そして、ThreadLocalをキーとして、Mapから格納されている変数、
設計上、開発者にとって、ThreadとThreadLocalMapは背後に隠されています.
ThreadLocalを直接操作することで変数の格納、取得、削除を完了します!
背後に隠されているものを理解してこそ、運行原理を深く理解することができる.
ソース:
ThreadクラスはThreadLocalの参照を持つ
ThreadLocalクラスの主な方法
現在のThreadのThreadMapセットを取得
変数をThreadMapに設定
mapが空の場合はThreadMapを初期化して保存します
最後に変数を返します
初期化変数の取得
このメソッドはprotected権限であり、ThreadLocalオブジェクトを作成するときに、このメソッドを再書き込みして初期化の目的を達成することができます.
初期化とは,変数をThreadLocalに入力し,ThreadLocalMapのvalueに格納することである.
例えば、複写初期化方法
ThreadLocalMapを作成し、Mapオブジェクトの参照をThreadのメンバー変数threadLocalsに渡す
これにより、ThreadLocal保存オブジェクトが実現される.
ThreadLocalに格納されている変数を取得します.
ThreadのThreadLocalMapを入手
==================================================================================
小さな例ですが、あまりよくありません.
同じスレッドにインスタンスを共有させ、異なるスレッドはそれぞれのインスタンスを使用し、互いに影響しません.
ThreadLocalの本格的な応用解釈:
各スレッドには独自の変数があり、Threadが終了しない限り、いつでも内部のThreadLocalMapを取り出し、ThreadLocal自身と組み合わせることで、Mapに格納されている変数を手に入れることができます.
どうしてこんなことになったの?メソッドチェーンで同じパラメータを渡す手間を解決しました!
適用シーン:
1つのスレッドが実行されており、多くのクラスの異なるメソッドを実行する必要があります.これらのメソッドは変数を使用しています.
では、この変数をどんどん後ろに伝えなければなりません.面倒です.
どのようにしてThreadのライフサイクル全体でこの変数を使用できるのか、ThreadLocalMapを使用して保存します.
各Threadには属性変数があります.
ThreadLocal.ThreadLocalMap threadLocals
ThreadLocalでは、内部クラス(Mapとして)が定義されています.
ThreadLocalMap map
このMapは特殊です.
key - ThreadLocal
value - 私たちが伝える変数
ThreadクラスのこのMapはどのように初期化されていますか?
ThreadLocalオブジェクトを作成し、getメソッドを呼び出して変数を取得すると、Threadから取得したMapが空の場合、
新しいMapが作成され、ThreadのthreadLocalsに参照が割り当てられます.
こうして、TheadにはMapの引用がある.
スレッドがまだ実行されている限り、currentThreadで独自のThreadLocalMapを得ることができます.
そして、ThreadLocalをキーとして、Mapから格納されている変数、
設計上、開発者にとって、ThreadとThreadLocalMapは背後に隠されています.
ThreadLocalを直接操作することで変数の格納、取得、削除を完了します!
背後に隠されているものを理解してこそ、運行原理を深く理解することができる.
ソース:
ThreadクラスはThreadLocalの参照を持つ
public class Thread implements Runnable {
...
ThreadLocal.ThreadLocalMap threadLocals = null;
...
}
ThreadLocalクラスの主な方法
public T get() {//threadLocal Map value
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);//map key: this
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;// value /
}
return setInitialValue();
}
現在のThreadのThreadMapセットを取得
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
変数をThreadMapに設定
mapが空の場合はThreadMapを初期化して保存します
最後に変数を返します
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
初期化変数の取得
このメソッドはprotected権限であり、ThreadLocalオブジェクトを作成するときに、このメソッドを再書き込みして初期化の目的を達成することができます.
初期化とは,変数をThreadLocalに入力し,ThreadLocalMapのvalueに格納することである.
protected T initialValue() {
return null;
}
例えば、複写初期化方法
ThreadLocalMapを作成し、Mapオブジェクトの参照をThreadのメンバー変数threadLocalsに渡す
これにより、ThreadLocal保存オブジェクトが実現される.
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
ThreadLocalに格納されている変数を取得します.
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);// Thread TheadLocalMap
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);// ThreadLocal key value
if (e != null)
return (T)e.value;
}
return setInitialValue();
}
ThreadのThreadLocalMapを入手
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
==================================================================================
小さな例ですが、あまりよくありません.
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateUtil {
private static final String DATA_FORMAT = "yyyy-MM-dd HH:mm:ss";
private static ThreadLocal threadLocal = new ThreadLocal() {
// : initialValue(),
// currentThread key ThreadLocalMap
// , Map。key ThreadLocal ,value
// Map Thread ThreadLocalMap【 currentThread Map , Map 】
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat(DATA_FORMAT);
}
};
public static SimpleDateFormat getDateFormat() {
// :threadLocal get()
//get() getMap(t),t currentThread, Thread threadLocals
// ThreadLocal.ThreadLocalMap threadLocals = null;
// ThreadLocalMap
// , initialValue() , , null
return threadLocal.get();
}
public static String format(Date date) {
return getDateFormat().format(date);
}
public static void main(String[] args) {
final Date date = new Date();
for(short i=0; i<10000; i++)
// : Thread t
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(DateUtil.getDateFormat().format(date));
}
}).start();
}
}