threadlocalとthreadメンバー変数にはまだ違いがあります。 Threadlocalクラスは、スレッドローカル変数を提供します。このローカル変数は、一般的なメンバー変数とは異なります。 threadlocal変数が複数のスレッドで使用される場合、各スレッドは変数のコピーを1つだけ取得できます。これはJava APIの説明です。 APIソースコードを読むことで、コピーではないことがわかりました。コピーの概念は何ですか?クローン?または何か他のもの、あいまいすぎます。
正確には、型threadlocalの変数内のレジストリ(Map <thread、t>)が変更されましたが、型Threadlocalの変数自体は確かに1つであり、これが本質です!
これが例です:
1。標準的な例
MythreadLocalクラスが定義されており、そのオブジェクトTLTが作成され、4つのスレッドで使用されます。その結果、4つのスレッドのTLT変数が共有されません。 2つ目は独自の使用です。これは、4つのスレッドがTLT(クローン)のコピーを使用していることを示しています。
/***スレッドロカルクラスを使用*/パブリッククラスMythReadLocal {// threadlocal変数を定義してintまたは整数データを保存しますプライベートスレッドロカル<integer> tl = new threadlocal <integer>(){@Overrideプロテクトintegervalue(){return 0; }}; public Integer getNextnum(){// tlの値を取得して1を追加し、t1 tl.set(tl.get() + 1)の値を更新します。 tl.getを返します(); }} / ***テストスレッド*/ public class testthread extends thread {private mythreadlocal tlt = new mythreadlocal(); public testthread(mythreadlocal tlt){this.tlt = tlt; } @Override public void run(){for(int i = 0; i <3; i ++){system.out.println(thread.currentthread()。 }}} / *** threadlocal Test*/ public class test {public static void main(string [] args){mythreadlocal tlt = new mythreadlocal();スレッドT1 = new TestThread(TLT);スレッドT2 = new TestThread(TLT);スレッドT3 = new TestThread(TLT);スレッドT4 = new TestThread(TLT); t1.start(); t2.start(); t3.Start(); t4.start(); }}
3つのスレッドに独立して番号が付けられており、お互いに影響を与えないことがわかります。
スレッド-0 1スレッド1 1スレッド-0 2スレッド1 2スレッド-0 3スレッド1 3スレッド2 1スレッド - 3スレッド2 2スレッド-3 2スレッド2 3スレッド - 3 3プロセス終了コードで仕上げます0
TLTオブジェクトは1つであり、Nonsense TLオブジェクトも1つです。これは、組み合わせ関係が1対1であるためです。ただし、スレッドの数が増えると、多くの整数オブジェクトが作成されます。整数とintがすでに一般的であるということです。したがって、整数のオブジェクトプロパティを感じることができません。
2。threadlocalを使用しないでください
ThreadLocalを使用しない場合は、MythReadLocalクラスを次のように再定義するだけです。
/ *** swretlocal class*/ public class mythreadlocal {private integer t1 = 0; public Integer getNextnum(){return t1 = t1+1; } // intまたは整数データを保存するようにthreadlocal変数を定義します//} //}; // // public Integer getNextnum(){// // tlの値を取得して1を追加し、t1 // tl.set(tl.get() + 1)の値を更新します。 // tl.getを返します(); //}}
次に、テストを実行します。
スレッド2 1スレッド2 2スレッド1 4スレッド1 6スレッド3 3スレッド3 9スレッド3 10スレッド1 8スレッド - 7スレッド-0 11スレッド-0 12スレッド2 5出口コードで仕上げられたプロセス0
ここから、4つのスレッドがTLT変数を共有し、各スレッドがTLTのプロパティを直接変更することがわかります。
3.自分でthreadlocalを実現します
パッケージcom.lavasoft.test2; java.util.collectionsをインポートします。 java.util.hashmapをインポートします。 java.util.mapをインポートします。 /***スレッドロカルクラスを使用*/パブリッククラスMythReadLocal {// threadlocal変数を定義してINTまたは整数データを保存しますプライベートcom.lavasoft.test2.threadlocal <integer> tl = new com.lavasoft.test2.threadlocal <integer>(){@Overrideプロテットインターガーバリュー0; }}; public Integer getNextnum(){// tlの値を取得して1を追加し、t1 tl.set(tl.get() + 1)の値を更新します。 tl.getを返します(); }} class threadlocal <t> {private map <thread、t> map = collections.synchronizedMap(new hashmap <thread、t>()); public threadlocal(){}保護されたt initialValue(){return null; } public t get(){thread t = thread.currentthread(); t obj = map.get(t); if(obj == null &&!map.containskey(t)){obj = initialValue(); map.put(t、obj); } objを返します。 } public void set(t value){map.put(thread.currentthread()、value); } public void remove(){map.remove(thread.currentthread()); }}
テストを実行します:
スレッド-0 1スレッド-0 2スレッド-0 3スレッド2 1スレッド2 2スレッド - 3スレッド2 3スレッド - 3スレッド1 1スレッド3 3スレッド1 2スレッド1 3プロセス終了コードで仕上げます0
驚くべきことに、Threadlocalのこの模倣版もうまく機能し、Java APIでThreadlocalの機能を実装しています。
4.現象を通して本質を参照してください
実際、プログラムの観点から見ると、TLT変数は確かに1つです。しかし、印刷された数字が互いに影響を与えないのはなぜですか?
整数を使用しているためですか? - - -いいえ。
その理由は、各スレッドがget()を呼び出すと、マップに存在しない場合にそれを作成するため、initialValue()およびget()保護されています。それが呼ばれると、新しい変数がタイプTで作成されます。もちろん、それらが新しく作成されるたびに、それぞれが互いに影響を与えることなく使用します。
本質を明確に見るために、整数を置き換えて、いくつかのクラスを書き直します。
パッケージcom.lavasoft.test2; java.util.collectionsをインポートします。 java.util.hashmapをインポートします。 java.util.mapをインポートします。 /***スレッドロカルクラスを使用*/パブリッククラスmythreadlocal {// intまたはintegerデータを保存するためにthreadlocal変数を定義する// privatelwerslocal <bean> tl = new swreetlocal <bean>(){private com.lavasoft.test2.threadlocal <bean> tl = newcom.lavasoft.test2.test2.test2.test2.test2.test2.test2.test2.test2.test2.test2。 initialValue(){return new Bean(); }}; @Override public String toString(){return "mythreadlocal {" + "tl =" + tl + '}'; } public bean getbean(){return tl.get(); }} class threadlocal <t> {private map <thread、t> map = collections.synchronizedMap(new hashmap <thread、t>()); public threadlocal(){}保護されたt initialValue(){return null; } public t get(){thread t = thread.currentthread(); t obj = map.get(t); if(obj == null &&!map.containskey(t)){obj = initialValue(); map.put(t、obj); } objを返します。 } public void set(t value){map.put(thread.currentthread()、value); } public void remove(){map.remove(thread.currentthread()); }}パッケージcom.lavasoft.test2; / ** *テストBean */ public class bean {private string id = "0";プライベート文字列名= "なし"; public bean(){} public bean(string id、string name){this.id = id; this.name = name; } public string getId(){return id; } public void setid(string id){this.id = id; } public string getname(){return name; } public void setName(string name){this.name = name; } public String showinfo(){return "bean {" + "id = '" + id +'/'' + "、name = '" + name +'/'' + '}'; }}パッケージcom.lavasoft.test2; / ***テストスレッド*/ public class testthread extends thread {private mythreadlocal tlt = new mythreadlocal(); public testthread(mythreadlocal tlt){this.tlt = tlt; } @Override public void run(){system.out.println( ">>>>:" + tlt); for(int i = 0; i <3; i ++){system.out.println(thread.currentthread()。getname()+"/t"+tlt.getbean()+"/t"+tlt.getbean()。showinfo()); }}}
次に、テストを実行します。
>>>>>:mythreadlocal {tl=com.lavasoft.test2.mythreadlocal$1@1de3f2d} >>>>>> >>>>>:mythreadlocal {tl=com.lavasoft.test2.bean@291aff bean {id = '0'、name = 'none'} swreat-2 com.lavasoft.test2.bean@fe64b9 bean {id = '0'、name = 'none'} com.lavasoft.test2.bean@ bean {id = '0'、name = 'none'} shood-2 com.lavasoft.test2.bean@fe64b9 bean {id = '0' '、name =' none '} shood-2 com.lavasoft.test2.bean@fe64b9 bean {id =' 0 '、name =' none 'なしbean {id = '0'、name = 'none'} swreet-0 com.lavasoft.test2.bean@291aff bean {id = '0' '、name =' none '} swreat-3 com.lavasoft.test2.bean@186db54 bean {id =' 0 com.lavasoft.test2.bean@186db54 bean {id = '0' '、name =' none '} com.lavasoft.test.test2.bean@291aff bean {id =' 0 '、name =' none '} swerd-0 com.lavasoft.test2.bean@291aff =' '' '0' com.lavasoft.test2.bean@291aff bean {id = '0' '、name =' none '} shood-1 com.lavasoft.test2.bean@291aff bean {id =' 0 '、name =' none '} exitコードで完成
印刷の結果から、MythreadLocalのTLTオブジェクトが実際に1つであり、TLTオブジェクトのTlswerllocalのTLオブジェクトも1つであることが明らかです。ただし、各スレッドにT1Tを使用すると、スレッドはBeanオブジェクトを再作成し、使用するためにThreadlocalマップに追加します。
Threadlocalに関するいくつかの誤解:
1。ThreadLocalは、Javaスレッドの実装です
Threadlocalは実際にJavaスレッドに関連していますが、Javaスレッドの実装ではなく、ローカル変数を維持するために使用されます。各スレッドについて、主にスレッドの競合を回避するために、独自の可変バージョンを提供し、各スレッドは独自のバージョンを維持します。互いに独立していると、変更は互いに影響を与えません。
2。threadlocalは各セッションに関連しています
名前が示すように、threadlocalはスレッドを対象としています。 Java Webプログラミングでは、各ユーザーにはセッションの最初から最後まで独自のセッション識別子があります。しかし、Threadlocalはセッションレイヤーにありません。実際、Threadlocalはユーザーセッションとは無関係です。サーバー側の動作です。サーバーが新しいスレッドを生成するたびに、独自のスレッドローカルを維持します。
この誤解に関して、私はそれがいくつかのアプリケーションサーバーに基づいた開発者のローカルテストの結果であるべきであると個人的に信じています。誰もが知っているように、一般的なアプリケーションサーバーはスレッドプールのセットを維持します。つまり、アクセスごとに、新しいスレッドが必ずしも生成されるわけではありません。代わりに、スレッドキャッシュプールがあります。アクセスするには、最初にキャッシュプールから既存のスレッドを見つけます。それらがすべてを使い果たした場合、新しいスレッドが生成されます。
したがって、開発者は通常自分自身をテストしている唯一の人であるため、サーバーの負担は非常に小さく、アクセスができるたびに同じスレッドの共有につながり、誤解が生まれます。各セッションにはスレッドローカルがあります。
3. threadlocalは各スレッドに関連しています。ユーザーがアクセスするたびに、新しいThreadlocalがあります。
理論的には、threadlocalは実際に各スレッドに対して関連しており、各スレッドには独自のthreadlocalがあります。ただし、上記のように、一般的なアプリケーションサーバーはスレッドプールのセットを維持します。したがって、異なるユーザーが同じスレッドを受信する場合があります。したがって、Headlocalベースを実行する場合、Threadlocal変数のキャッシュを回避するように注意する必要があります。
4。ユーザーアクセスごとに、ThreadLocalを複数回使用できます。
Threadlocalは両刃の剣であり、使用すれば非常に良い結果をもたらすことができると言えます。ただし、threadlocalがうまく使用されていない場合、グローバル変数と同じになります。コードを再利用することはできず、独立してテストすることはできません。再利用された可能性のあるいくつかのクラスは、現在糸状変数に依存しているためです。スレッドローカルがない場合、これらのクラスは利用できなくなります。私は個人的には、糸localはよく使用されており、言及する価値があると思います
1.現在のセッションユーザーを保存します:Quake want jert
2。WebworkのActionContextなどのコンテキスト変数を保存します
3。SpringHibernate Ormセッションなどのストアセッション