ThreadLocalのスレッドは、スレッドセーフ現在のスレッドへのアクセスのみで、ローカル変数、です。各スレッドは、ThreadLocalのが唯一の単純なコンテナの役割を果たしている必要があることを確認するために、アプリケーションレベルで異なるオブジェクトに割り当てられています。
ThreadLocalのクラスでは、唯一の4つの方法は、以下の方法であり、非常に簡単です:
- 値voidセット(Object値)は、現在のスレッドのスレッドローカル変数を設定します。
- パブリックオブジェクトのget()メソッドは、スレッドローカル変数に対応する現在のスレッドを返します
- 公共ボイドのremove()削除された現在のスレッドのローカル変数の値は、目的は、メモリの使用量を減らすことです。動作する必要はありませんが、それはメモリ速度の回復をスピードアップすることができ、スレッドの終了、スレッドローカル変数は自動的にゴミであるべきとき、ことに留意すべきであるので、この方法は、明確なスレッドローカル変数を表示するために呼び出されます。
- 保護オブジェクトはinitialValue()が明らかにカバー設計サブクラスを可能にするために、保護する方法であって、スレッドローカル変数の初期値に戻ります。この方法は、遅延呼び出しメソッドである、最初のコールは、(取得する)または(場合)スレッドが実行される設定し、一度だけ実行されます。直接リターンのデフォルトのThreadLocalはnull。
どのようにこれらのオブジェクトは、現在のスレッドのみのアクセスであることを確認ThreadLocalの?起動するように設定()メソッドを起動します。
公共 ボイド集合(T値){ スレッドT = にThread.currentThread()。 ThreadLocalMap地図 = GetMapリクエスト(T)。 もし(!マップ= ヌル) map.set(この、値); 他 createMap(トン、値); }
最初のときにオブジェクトセット現在のスレッドを取得し、その後、GetMapリクエスト()メソッドを介してスレッドThreadLocalMapを得るために、値はThreadLocalMapに格納されています。このマップは、値は、我々が必要とする値であり、キーThreadLocalの現在のオブジェクトです。そして、操作のget()メソッドは、これはデータの性質が出マップです。
パブリックTのget(){ スレッドT = にThread.currentThread()。 ThreadLocalMap地図 = GetMapリクエスト(T)。 もし(!マップ= ヌル){ ThreadLocalMap.Entry電子 = map.getEntry(これを)。 もし(!E = nullの) リターン(T)e.value。 } を返す)(setInitialValueします。 }
現在のスレッドをThreadLocalMap得る()メソッドを取得し、その後、独自の内部を取得する鍵として実際のデータによる。オブジェクト参照があった、これらの変数は、Threadクラスの内部に保持され、スレッドが終了していないです。私は問題を持っているでしょう。スレッドの終了コードするとき、次のように:
プライベート ボイドの出口(){ 場合(グループ=!ヌル){ group.threadTerminated(この); グループ = nullを。 } 標的 = ヌル。 / * 加速资源清理* / threadLocals = nullを。 inheritableThreadLocals = nullを。 inheritedAccessControlContext = nullを。 ブロッカー = nullを。 たuncaughtExceptionHandler = nullを。 }
従って、現在のスレッドプールのスレッドが終了しないことを意味する(固定サイズのスレッドプールスレッドが常に存在しているなど)。この場合は、システムに大きなオブジェクトの数は、ThreadLocalのメモリリークを表示されることがあり起こすの設定を使用することができ、それを清掃しないで後に数回、オブジェクト、オブジェクトはもはや有益ではありませんが、回復することができませんでした。あなたは、オブジェクトのタイムリーな回復をしたい場合は、変数を削除するThreadLocal.remove()メソッドを使用することができます。ThreadLocal変数のために、手動でNULLに設定され、すべてのスレッドのローカル変数を対応このThreadLocalのは撤回される可能性があります。次に例を示します。
パッケージcom.wyw.xc.test.threadlocal。 輸入java.text.SimpleDateFormatの。 輸入java.util.Date; 輸入java.util.concurrent.CountDownLatch。 輸入java.util.concurrent.ExecutorService。 輸入java.util.concurrent.Executors。 パブリック クラスはThreadLocalDemo_Gc { 静的 揮発性のThreadLocal <てSimpleDateFormat> TL = 新規のThreadLocal <てSimpleDateFormat> (){ @Overrideが 保護 ボイドファイナライズ()スローされたThrowable { System.out.printlnは(これ .toStringは()+ "GCです" )。 } }。 静的 揮発たCountDownLatchのCD = 新たCountDownLatch(10000 ); パブリック 静的 クラスはparsedataは実装のRunnableは{ int型、I = 0 。 公共はparsedata(int型I){ この .I = I。 } @Override 公共 ボイドラン(){ しようと{ 場合(tl.get()== nullの){ tl.set(新SimpleDateFormat( "YYYY-MM-DD HH:MM:SS" ){ @Overrideは 保護 ボイド(ファイナライズ)をスローしたThrowable { System.out.printlnは(この .toString()+ "がGCです" )。 } })。 System.out.println(にThread.currentThread()のgetId()。 + ":てSimpleDateFormatを作成します" ); } 日付T = tl.get()( "2019年8月4日午後06時40分" + I 60%を解析。)。 } キャッチ(例外e){ e.printStackTrace(); }最後に{ cd.countDown()。 } } } パブリック 静的 ボイドメイン(文字列[]引数)スローInterruptedExceptionあるが{ ExecutorServiceのES = Executors.newFixedThreadPool(10 )。 以下のために(int型 ; I <10000は、I ++は、I = 0 ){ es.execute(新しいはparsedata(I))を、 } cd.await()。 System.out.println( "完全なミッション!!" ); TL = nullを。 System.gc(); System.out.println( "完全な最初のGC!" ); TL = 新しいのThreadLocal <てSimpleDateFormat> (); CD = 新たCountDownLatch(10000 ); 以下のために(int型 ; I <10000は、I ++は、I = 0 ){ es.execute(新しいはparsedata(I))を、 } cd.await()。 Thread.sleep( 1000年); System.gc(); System.out.println( "完全な二GC !!" ); } }
まず、スレッドプール内の各10件のスレッドはSimpleDateFormatのオブジェクトのインスタンスを作成し、初めてGCのために、あなたはThreadLocalのオブジェクトが復元されている見ることができます。タスクをもう一度送信する場合、この時間はまた、10のSimpleDateFormatオブジェクト、及び第2のGCを作成しました。我々は手動)(これらのオブジェクトを削除する必要はありませんが、システムはそれらを回復することは可能ですが、10個のオブジェクトは、完全な回復を作成した2番目のGC後初めて。
各スレッドは、競争力のあるプロセスの共有オブジェクトを簡単にパフォーマンスの損失につながる場合は、システムのパフォーマンス上の別のオブジェクトは、役に立つ割り当てられているために、各スレッドが別のオブジェクトが割り当てられているため、我々はThreadLocalの使用を検討してください。