ThreadLocalの設計原理

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の欠点

  • 不適切な使用容易なメモリフットプリントが大きすぎます。長いスレッドなどのプライベート変数の生存時間。

おすすめ

転載: www.cnblogs.com/datartvinci/p/11069913.html