1. ThreadLocalの
1.1はじめに
データのみ、指定したスレッドに格納された後にThreadLocalは、データストアに取得することができ、あなたが別のスレッドにデータを可視得ることができない、あなたが指定したスレッドにデータを格納することができ、それを通して雌ねじデータ・ストレージ・クラス、です。
これは、次の要件を満たすことができます。
- 別のスレッドで同じ変数が別のコピーを持っている必要があります
- 多くの場合、静的メソッドで使用される、スレッドの作成時に割り当てることができません
1.2アプリケーションのシナリオ
- データベース接続プール
- 的セッションを休止
- 他のクラスはスレッドセーフではありませんロックを複数のスレッドで使用するために
1.3アプリケーション例
同時に、唯一の2つだけの選択肢マルチスレッド環境を使用して、1つの解析式をサポートすることができますので、時間分解SimpleDateFormatクラスは、スレッドセーフの典型的な例であります:
- ロックアクセス
- ThreadLocalのことで、そのためのスレッドはスレッドプライベートのSimpleDateFormatオブジェクトを保持しています
private static final ThreadLocal<SimpleDateFormat> threadLocal = new ThreadLocal<>();
static String format(Date date, String pattern) {
SimpleDateFormat simpleDateFormat = threadLocal.get();
if (simpleDateFormat == null) {
simpleDateFormat = new SimpleDateFormat();
threadLocal.set(simpleDateFormat);
}
simpleDateFormat.applyPattern(pattern);
return simpleDateFormat.format(date);
}
2.設計の原則
次はいつでもスレッドが独自のスレッドプライベート変数を持つことができるように、自分自身のプログラムを設計してみてください。デザインを通じてJDKプログラムの進化を理解するのに役立ちます。
あなたは、保存するかを選択できる2つの場所があるプライベート変数をスレッド:
- 内部スレッド
- 外部集合
2.1スレッドに格納されています
2.1.1定義
考えるための最初の方法は、最も簡単で、複数のスレッドを地図でプライベート変数を保持することです。
public class ThreadLocalInside extends Thread {
WeakHashMap<Object, Object> threadLocals = new WeakHashMap<>();
}
2.1.2ユースケース
別のスレッドプライベート変数を区別するために彼自身の柔軟なセットアップキー。
static String format(Date date, String pattern) {
ThreadLocalInside thread = (ThreadLocalInside) Thread.currentThread();
Class clazz = SimpleDateFormat.class;
SimpleDateFormat simpleDateFormat = (SimpleDateFormat) thread.threadLocals.get(clazz);
if (simpleDateFormat == null) {
simpleDateFormat = new SimpleDateFormat();
thread.threadLocals.put(clazz, simpleDateFormat);
}
simpleDateFormat.applyPattern(pattern);
return simpleDateFormat.format(date);
}
2.1.3利点
- スレッドの安全性。どのスレッドへのアクセスの問題はありません。
2.1.4短所
- 不適切な使用容易なメモリフットプリントが大きすぎます。プライベート変数の生存時間限りのスレッドがガベージコレクタを使用することはできません。
- カップリング。新しいAPIは、結合スレッドのクラスが必要です。
- 管理不便。あなたはすべてのスレッドでスレッドプライベート変数のコピーを削除したい場合は、非常に難しいです。
外部コレクションに保存されている2.2
2.2.1コードの実装
public class ThreadLocalOutside extends WeakHashMap<Thread, HashMap<Object, Object>> {
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
@Override
public HashMap<Object, Object> put(Thread key, HashMap<Object, Object> value) {
lock.writeLock().lock();
try {
return super.put(key, value);
} finally {
lock.writeLock().unlock();
}
}
public HashMap<Object, Object> get(Thread key) {
lock.readLock().lock();
try {
return super.get(key);
} finally {
lock.readLock().unlock();
}
}
}
2.2.2ユースケース
private static final ThreadLocalOutside THREAD_LOCAL_MANAGER = new ThreadLocalOutside();
static String format(Date date, String pattern) {
Thread thread = Thread.currentThread();
HashMap<Object, Object> threadLocalVariable = THREAD_LOCAL_MANAGER.get(thread);
Class clazz = SimpleDateFormat.class;
SimpleDateFormat simpleDateFormat = (SimpleDateFormat) threadLocalVariable.get(clazz);
if (simpleDateFormat == null) {
simpleDateFormat = new SimpleDateFormat();
threadLocalVariable.put(clazz, simpleDateFormat);
}
simpleDateFormat.applyPattern(pattern);
return simpleDateFormat.format(date);
}
2.2.3利点
- デカップリング。スレッドAPIに参加する必要はありません雄ねじプライベート変数を管理するために別のクラスを使用します。
- 管理が簡単。あなたは簡単にプライベート変数内のすべてのスレッドを削除することができます。
2.2.4短所
- パフォーマンスの問題。スレッド不安をロックしないようにする必要があります。
- 不適切な使用容易なメモリフットプリントが大きすぎます。プライベート変数の生存時間限りのスレッドがガベージコレクタを使用することはできません。
3. JDKの設計、内部および外部の統合
ThreadLocalのJDKは、スレッドに格納された上記の二つのデザインのアイデアを、含まれていますが、これは外部のクラスによって操作するためのAPIを提供します。
新しいデザイン紹介:キーのセットとしてプライベート変数のThreadLocalオブジェクトの使用を、各ThreadLocalのオブジェクトは、スレッドプライベート変数の種類を表します。この設計では、スレッドプライベート変数を管理するための痛みのポイントに対処します。
- あなたは、スレッドプライベート変数の管理がより便利になるように、オブジェクトが作成されたどのように多くのThreadLocalのスレッドプライベート変数、多くの種類を持っている必要がある場合。
- あなたはすべてのスレッドでスレッドプライベート変数を削除したい場合は、それはもはや、ガベージコレクタへの他にThreadLocalオブジェクトを参照することはできません。
3.1コードの実装
読者の注意を保つためにはThreadLocalの内部のWeakHashMap ThreadLocalMapの代わりに、ここで使用されるハッシュテーブル分散の弱参照実装の詳細です。
3.1.1弱参照コレクション
この短いコレクションは、次の二つの特徴:
- キーは、もはや他のオブジェクトから参照されて設定されていない場合は、ガベージコレクタはこのキーオブジェクトのうち、再利用します。
- あなたは()入れて呼び出すと、(取得)し、他の方法、Keyオブジェクトがガベージされていることを、要素に一方向ハッシュテーブルで削除されます。
- ハッシュ衝突は、競合を解決するために、オープンアドレス指定方法を使用してリスト方式、ThreadLocalMapを使用する場合のWeakHashMap(メモリを節約するために配列を使用)、利点が簡単です。
3.1.2 JDK実装のコテージバージョン
public class Thread2 extends Thread {
//ThreadLocal作为key,一个ThreadLocal代表一种线程私有变量
WeakHashMap<ThreadLocal2, Object> threadLocals;
}
class ThreadLocal2<T> {
//模板方法
protected T initialValue() {
return null;
}
public T get() {
Thread2 thread = (Thread2) Thread.currentThread();
WeakHashMap<ThreadLocal2, Object> threadLocalMap = thread.threadLocals;
if (threadLocalMap != null) {
Object value = threadLocalMap.get(this);
if (value != null) {
return (T) value;
}
}
T value = initialValue();
if (threadLocalMap != null) {
threadLocalMap.put(this, value);
} else {
//懒加载,大部分线程不使用threadLocal,因此能节约不少内存
thread.threadLocals = new WeakHashMap<>();
thread.threadLocals.put(this, value);
}
return value;
}
public void set(T object) {
Thread2 thread = (Thread2) Thread.currentThread();
WeakHashMap<ThreadLocal2, Object> threadLocalMap = thread.threadLocals;
if (threadLocalMap != null) {
threadLocalMap.put(this, object);
} else {
//懒加载,大部分线程不使用threadLocal,因此能节约不少内存
thread.threadLocals = new WeakHashMap<>();
thread.threadLocals.put(this, initialValue());
}
}
}
3.2ユースケース
それを達成するために、ほぼ正確に同じとJDKを使用するのThreadLocal
private static final ThreadLocal2<SimpleDateFormat> threadLocal = new ThreadLocal2<>() ;
static String format(Date date, String pattern) {
SimpleDateFormat simpleDateFormat = threadLocal.get();
if (simpleDateFormat == null) {
simpleDateFormat = new SimpleDateFormat();
threadLocal.set(simpleDateFormat);
}
simpleDateFormat.applyPattern(pattern);
return simpleDateFormat.format(date);
}
3.3利点
- 高性能:コレクションはスレッドのスレッドプライベート変数、ロックなしで保存されています。
- デカップリング:外部オブジェクトは、APIを提供します。
- 外部オブジェクトは、もはや他のオブジェクトによって参照され、ガベージコレクトされているキーを、保持するために、スレッド内のハッシュテーブルなどの主要な外部の物体が、弱参照との双方向のハッシュテーブルで削除されますに、要素:使用JDKのガベージコレクションのメカニズムKeyオブジェクトがガベージされていることを条件とします。
- 管理が簡単。簡単にプライベート変数内のすべてのスレッドを削除することができ、単純に対応THREADLOCALへの参照を削除します。
単にそのかすに本質を選択します。
3.4の欠点
- 不適切な使用容易なメモリフットプリントが大きすぎます。長いスレッドなどのプライベート変数の生存時間。