ThreadLocalの動作原理

3507 ワード

 1.概要

ThreadLocalは、マルチスレッドプログラムの同時問題を解決するための新しい考え方を提供しています.このツールクラスを使用すると、美しいマルチスレッドプログラムを簡潔に作成できます.
ThreadLocalは文字通り「ローカルスレッド」と思われがちです.実際、ThreadLocalはThreadではなく、Threadのローカル変数であり、ThreadLocalVariableと命名すると理解しやすいかもしれません.
ThreadLocalを使用して変数を維持する場合、ThreadLocalは、その変数を使用するスレッドごとに独立した変数のコピーを提供するので、各スレッドは、他のスレッドに対応するコピーに影響を与えることなく、独立して自分のコピーを変更することができます.

2.ThreadLocalのインタフェース方法

ThreadLocalクラスインタフェースは簡単です.4つの方法しかありません.まず、次のことを理解します.
void set(Object value)
現在のスレッドのスレッドローカル変数の値を設定します.
public Object get()
このメソッドは、現在のスレッドに対応するスレッドローカル変数を返します.
public void remove()
現在のスレッドのローカル変数の値を削除します.これは、JDK 5.0に追加された方法で、メモリの使用量を減らすためです.スレッドが終了すると、スレッドのローカル変数が自動的にゴミに回収されるため、このメソッドを明示的に呼び出してスレッドのローカル変数を消去することは必須ではありませんが、メモリ回収の速度を速めることができます.
protected Object initialValue()
スレッドのローカル変数の初期値を返します.この方法はprotectedの方法で、明らかにサブクラスを上書きするために設計されています.この方法は,スレッドがget()またはset(Object)を1回目に呼び出したときに実行され,1回のみ実行される遅延呼び出し方法である.ThreadLocalのデフォルトインプリメンテーションはnullを直接返します.
特筆すべきは、JDK 5.0では、ThreadLocalは汎用型をサポートしており、クラス名はThreadLocalに変更されています.APIメソッドもそれに応じて調整され、新しいバージョンのAPIメソッドはvoid set(T value)、T get()およびT initialValue()である.

3.実現原理

ThreadLocalはどのようにして各スレッドの変数のコピーを維持しますか?実装の考え方は簡単です.ThreadLocalクラスには、各スレッドの変数コピーを格納するMapがあり、Mapの要素のキーはスレッドオブジェクトであり、値はスレッドの変数コピーに対応します.簡単な実装バージョンを提供できます.
public class ThreadLocal{ 
     private Map values =Collections.synchronizedMap(newHashMap());  
      public Object get(){ 
             Thread curThread = Thread.currentThread(); 
             Object o = values.get(curThread); 
             if (o == null||!values.containsKey(curThread)){ 
                   o = initialValue(); 
                   values.put(curThread, o); 
              } 
             return o;  
     } 


     public void set(Object newValue){ 
        values.put(Thread.currentThread(), newValue); 
     } 


     public Object  initialValue(){ 
          return null; 
      } 
} 

4.Thread同期機構の比較

ThreadLocalはスレッド同期メカニズムと比較してどのようなメリットがありますか?ThreadLocalとスレッド同期メカニズムは、マルチスレッド内の同じ変数のアクセス競合の問題を解決するために使用されます.
同期メカニズムでは、オブジェクトのロックメカニズムによって、同じ時間に1つのスレッドのみが変数にアクセスすることを保証します.このとき,この変数は複数のスレッドで共有されており,同期メカニズムを用いてプログラムが変数をいつ読み書きするか,いつオブジェクトをロックする必要があるか,いつオブジェクトロックを解放するかなどの煩雑な問題を慎重に分析することが要求され,プログラム設計と作成の難易度が相対的に大きい.
一方、ThreadLocalは、マルチスレッドの同時アクセスを別の角度から解決します.ThreadLocalは、各スレッドに独立した変数のコピーを提供し、複数のスレッドによるデータへのアクセス競合を分離します.各スレッドには独自の変数のコピーがあるため、その変数を同期する必要はありません.ThreadLocalはスレッドの安全な共有オブジェクトを提供し,マルチスレッドコードを記述する際に不安全な変数をThreadLocalにカプセル化することができる.
ThreadLocalでは任意のタイプのオブジェクトを持つことができるため、低バージョンJDKで提供されるget()はObjectオブジェクトを返し、タイプ変換を強制する必要があります.しかし、JDK 5.0は汎用的によくこの問題を解決し、ある程度ThreadLocalの使用を簡略化し、コードリスト9 2はJDK 5.0の新しいThreadLocalバージョンを使用した.
要約すると、マルチスレッドリソース共有の問題では、同期メカニズムは「時間で空間を変える」方式を採用し、ThreadLocalは「空間で時間を変える」方式を採用している.前者は1つの変数のみを提供し、異なるスレッドをキューに並べてアクセスさせ、後者は各スレッドに1つの変数を提供するため、互いに影響を及ぼさずに同時にアクセスすることができる.
一般に,マルチスレッド環境で共有できるのは無状態のBeanのみであり,SpringではほとんどのBeanがsingleton役割ドメインとして宣言できることを知っている.Springは、RequestContextHolder、T r a n s c t ionSynchronizationManager、LocaleContextHolderなどのBeanの非スレッドセキュリティ状態をThreadLocalで処理し、ステータスのあるBeanがマルチスレッドで共有できるようにするためです.

5.まとめ

もちろんThreadLocalは同期機構に代わるものではなく,両者が向いている問題領域は異なる.同期メカニズムは、複数のスレッドが同じリソースに対する同時アクセスを同期するためであり、複数のスレッド間で通信を行うための有効な方法である.一方、ThreadLocalは、複数のスレッドを分離したデータ共有であり、複数のスレッド間でリソース(変数)を共有することは根本的に行われていないため、複数のスレッドを同期する必要はありません.したがって、複数のスレッド間で通信する必要がある場合は、同期メカニズムを使用します.複数のスレッド間の共有競合を分離する必要がある場合は、ThreadLocalを使用します.これにより、プログラムがより読みやすく、簡潔になります.