2009-09-29 5 views
28

可能な重複:When and how should I use a Threadlocal variableThreadLocalの目的は?


のThreadLocalの目的変数はThreadLocal変数を含むオブジェクトにアクセスするすべてのスレッドに対してローカルであることをhere状態与えられます。 ThreadLocal変数をクラスのメンバとして使用し、Thread自体にローカル変数を持たせるのではなく、スレッドに対してローカルにするという点でどのような違いがありますか?

答えて

71

スレッドは実行単位なので、複数のスレッドが同じコードを同時に実行できます。複数のスレッドが同時にオブジェクト/インスタンス上で実行する場合、インスタンス変数を共有します。各スレッドは独自のローカル変数を持ちますが、パラメータを渡さずにオブジェクト間で共有することは困難です。

これは例として最もよく説明されています。ログインしたユーザーを取得してコードを実行するサーブレットがあるとします。

doGet(HttpServletRequest req, HttpServletResponse resp) { 
    User user = getLoggedInUser(req); 
    doSomething() 
    doSomethingElse() 
    renderResponse(resp) 
} 

doSomething()メソッドがユーザーオブジェクトにアクセスする必要がある場合はどうなりますか?各スレッドは同じユーザーオブジェクトを使用するため、ユーザーオブジェクトをインスタンス変数または静的変数にすることはできません。あなたは、パラメータとして周りのユーザーオブジェクトを渡すことができますが、これはすぐに乱雑になり、すべてのメソッド呼び出しにユーザーオブジェクトをリーク:

doGet(HttpServletRequest req, HttpServletResponse resp) { 
    User user = getLoggedInUser(req); 
    doSomething(user) 
    doSomethingElse(user) 
    renderResponse(resp,user) 
} 

よりエレガントな解決策はThreadLocalの

doGet(HttpServletRequest req, HttpServletResponse resp) { 
    User user = getLoggedInUser(req); 
    StaticClass.getThreadLocal().set(user) 
    try { 
    doSomething() 
    doSomethingElse() 
    renderResponse(resp) 
    } 
    finally { 
    StaticClass.getThreadLocal().remove() 
    } 
} 
にユーザーオブジェクトを置くことです

今それらの厄介な追加パラメータに頼る必要がないローカルスレッドからそれを抽出して、それを手に入れることができます任意の時点でユーザーオブジェクトを必要とする任意のコード、:

User user = StaticClass.getThreadLocal().get() 

この方法を使用する場合は、finallyブロック内のオブジェクトを再度削除することに注意してください。そうしないと、スレッドプール(Tomcatアプリケーションサーバーなど)を使用する環境でユーザーオブジェクトがハングアップする可能性があります。

編集:静的クラスのコード

class StaticClass { 
    static private ThreadLocal threadLocal = new ThreadLocal<User>(); 

    static ThreadLocal<User> getThreadLocal() { 
    return threadLocal; 
    } 
} 
+1

StaticClassとは何ですか?スレッドを拡張するクラス? – Ajay

+0

StaticClassは、ThreadLocalオブジェクトを保持する便利な方法です。この例を編集してStaticClassのコードを追加します。 – leonm

+7

私はいつもよりエレガントだとは言っていませんが、より便宜です –

7

Threadオブジェクトは内部データメンバーを持つことができますが、Threadオブジェクトへの参照を持つ(または取得できる)誰でもアクセスできます。 ThreadLocalは、それにアクセスする各スレッドにのみ意図的に関連付けられます。利点は、並行処理の問題がないことです(ThreadLocalのコンテキスト内で)。スレッドの内部データメンバには、共有状態が行うすべての同時実行性の問題があります。

結果を特定のスレッドに関連付ける考えを説明しましょう。

public class MyLocal<T> { 
    private final Map<Thread, T> values = new HashMap<Thread, T>(); 

    public T get() { 
    return values.get(Thread.currentThread()); 
    } 

    public void set(T t) { 
    values.put(Thread.currentThread(), t); 
    } 
} 

が今よりもそれに多くのがありますが、あなたが見ることができるように返された値が現在のスレッドによって決定されます。ThreadLocalをの本質は、このようなものです。それで、各スレッドにローカルという理由があります。

+0

各スレッドの意味に意図的に関連付けられていますか。スレッド自体はオブジェクトなのですか?実際にはスレッドに関連付けられているということは、実際にはスレッドオブジェクトに関連付けられていることを意味しますか? – Ajay

+0

@Ajay:はい。 ThreadLocalインスタンスは、Threadオブジェクトに関連付けられた準プライベートデータ構造を介してThreadオブジェクトに関連付けられます。 "package private"メンバを参照してください。Thread.threadLocalsとThread.inherittableThreadLocals –

+0

@Stephen:スレッドクラスのメンバを持つのと比べて、threadLocalを持つ点でどのような違いがありますか。 – Ajay

1

ThreadLocalsの利点は、単純なバニラのスレッドやスレッドのサブクラスで実行されるメソッドで使用できることです。

これに対して、あなたのスレッドのローカルをThreadのカスタムサブクラスのメンバーとして実装する必要がある場合、実行できないことがたくさんあります。たとえば、既存のバニラスレッドインスタンスでメソッドを実行する必要がある場合、アプリケーションに問題が発生します。すなわち、アプリケーションライターが書き込まず、変更できないライブラリコードによって作成されたインスタンス。

5

のThreadLocalはwebアプリケーションに非常に有用です。典型的なパターンは、Webリクエストの処理の開始時(通常はサーブレットフィルタ内)の状態がThreadLocal変数に格納されていることです。要求の処理はすべて1スレッドで行われるため、要求に関与するすべてのコンポーネントはこの変数にアクセスできます。

2

この問題領域はウィキペディアentry aboutです。私たちの環境では、通常は物事をリクエストするためにローカルに保つために使用されます。サーバー側では、リクエストはほとんどが単一のスレッドによって処理されます。あなたのデータをローカルに保存するには、セッションデータをスレッドローカル変数に格納します。このデータは他のリクエスト(スレッド)には見えないため、他のリクエストと同期させる必要はありません。

また、ではなく、スレッドセーフであるJAVA API構造体があることを忘れないでください。 DateFormat。 DateFormatの静的インスタンスは、サーバー側では機能しません。

実際には、自分のプライベートなデータコピーをロックやモニタで処理するよりも、マルチスレッドプログラミングを扱う方が簡単です。

10

あなたがスレッドを拡張するクラスのインスタンスはない実際のJavaスレッドと同じものであることを認識する必要があり、あなたのコードを実行し、それを実行し、「実行ポインタ」として想像できる( )。

このようなクラスのインスタンスは、を表すJavaスレッドであり、それを操作する(例えば割り込みする)ことはできますが、それらは単なる通常のオブジェクトであり、そのメンバには保持できるすべてのスレッドからアクセスできますオブジェクトへの参照です(not hard)。

メンバーを非公開にし、それがrun()またはそれから呼び出されたメソッドによってのみ使用されるようにすることはできますが(パブリックメソッドはほかのスレッドからも呼び出すことができます)、これはエラーが起こりやすくもっと複雑なシステムでは、スレッドのサブクラスにデータを保存したくない(実際には、Threadをサブクラス化するのではなく、Runnableを使用する必要があります)。

ThreadLocalは、スレッド単位のデータを持つための簡単で柔軟な方法です。は他のスレッドが同時にアクセスすることはできません。大きな労力や設計の妥協を必要としません。