ThreadLocalのは何ですか
JDK 1.2の初期バージョンとして同時マルチスレッドプログラムの問題を解決するための新しい方法を提供THREADLOCAL、java.lang.ThreadLocalを提供します。このツールを使用すると、美しいマルチスレッドプログラムを書くための非常に単純なクラスであることができます。
ThreadLocal変数のメンテナンスを使用する場合、ThreadLocalのは、変数独立変数のコピーを使用して、各スレッドに提供、各スレッドは独立してコピーを対応する他のスレッドに影響を与えることなく、そのコピーを変更することができます。
ビューのスレッドの観点から、ターゲット変数は、「ローカル」クラス名を表現することを意図しているスレッドローカル変数、のようなものです。
そのため、Javaでスレッドローカル変数を作成するためのコードは、このようにスレッドローカル変数は中のJava開発者の人気が十分ではありません引き起こし、比較的少数の不器用されるように。
ThreadLocalのインタフェースメソッド
ThreadLocalのクラスインターフェイスは非常にシンプルですが、唯一の4つの方法は、のは、見てみましょう:
-
空のセット(Object値)現在のスレッドのスレッドローカル変数の値。
-
パブリックオブジェクトのget()メソッドは、スレッドローカル変数に対応する現在のスレッドを返します。
-
公共ボイド削除()削除された現在のスレッドのローカル変数の値は、目的は、JDK 5.0の新しい方法であるメモリ使用量を低減することです。とても明示的にローカル変数が動作するために必要とされていないが、それはメモリ速度の回復をスピードアップすることができますスレッドをクリアするには、このメソッドを呼び出して、スレッドの終了、スレッドローカル変数は自動的にゴミであるべきとき、ことに留意すべきです。
-
保護されたオブジェクトはinitialValue()明らかにできるように、保護されたサブクラスに設計カバーの方法であって、スレッドローカル変数の初期値に戻ります。この方法では、遅延呼び出しに、コールget()メソッドであるかのセット(オブジェクト)とき実行スレッドは初めて、と一度だけ実行します。直接リターンのデフォルトのThreadLocalはnull。
これは、JDK5.0で、ThreadLocalのは、ジェネリックをサポートしていることを言及する価値がある、クラス名のクラスはThreadLocalのになっています。APIメソッドに応じて調整され、APIメソッドの新バージョンがvoidセット(T値)あり、Tは、(取得)およびTはinitialValue()。
1、の定義
ThreadLocalのスレッドローカル変数貯蔵容器は可変で、この容器は可変スレッドの任意の位置に取ることができる変数に格納されます。
別々のスレッドを使用することでThreadLocalの変数は、他のスレッドは、変数のセキュリティを確保するために使用することはできません
2、例
public class TestDemo {
//用一个静态的变量来记录ThreadLocal对象,方法在任何地方法直接调用
static ThreadLocal<String> local = new ThreadLocal<>();
public static void main(String[] args) {
new Thread(){
public void run(){
//在线程的任意地方设置变量
local.set("你");
method();
}
}.start();
new Thread(){
public void run(){
local.set("好");
method();
}
}.start();
}
public static void method(){
//可以在当前线程的任意地方获取变量
System.out.println(local.get());
}
}
3. 実用的なビジネスニーズ
デバイス2つの非同期コールバックインタフェース、データが同じレコードの場合は、データの整合性を確保するために、あなたはどのように行うのでしょうか?
既知のインタフェースは、実行されるコールバックのかを知ることができない、ランダムな順序をコールバック
表の構造:
id名num個
二コールバックパラメータは、テーブルのフィールドのリターンです
例えば:
コールバックインタフェースのnum個のフィールドを返します。
2つのリターンコールバックインタフェース名フィールド
彼らは共通のアイデンティティを持っていないが、まだ記録がなければならない、あなたはどのように行うのでしょうか?
私のアプローチがスタートです。
最近10Sのテーブルでクエリデータに、更新操作に存在する場合、挿入されていない場合
と同じ方法で、別のインターフェイスその逆と副更新操作に存在する場合、レコードが存在するかどうかをまずチェック、それが挿入されていません
しかし、その欠点は、10秒以内にレコードのみを記録し、また明白です。
そこにThreadLocalでこの時間
直接コードに
public class Test {
//静态类 方便调用
static ThreadLocal<Ta> local = new ThreadLocal<>();
public static void main(String[] args) {
//无论先调用哪个接口 都先将这个值插入到ThreadLocal中
Ta ta = new Ta();
ta.setId(1);
local.set(ta);
//因为我们不知道哪个回调先调用,所以先判断是否存在了
if(local.get().getId()!=null){
//存在的情况就在另一个回调中获取上一个回调中插入的值
Ta ta1 = new Ta();
ta1.setId(local.get().getId());
ta1.setName("成功了");
//记得再保存数据的时候先remove,再set进去
local.remove();
local.set(ta1);
//这个时候我们就可以插入数据库了,保证了数据的完整性
}
method();
}
public static void method(){
//可以在当前线程的任意地方获取变量
//加上 .toString() 是因为我用的是实体类
System.out.println(local.get().toString());
}
public static class Ta{
//实体类
private Integer id;
private String name;
private Integer num;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getNum() {
return num;
}
public void setNum(Integer num) {
this.num = num;
}
@Override
public String toString() {
return "Ta{" +
"id=" + id +
", name='" + name + '\'' +
", num=" + num +
'}';
}
}
}
これは、シングルスレッドである、上記のビジネスニーズを完了します。
4.複数のスレッドでのThreadLocalの使用
package com.test;
public class TestNum {
// ①通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值
private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() {
public Integer initialValue() {
return 0;
}
};
// ②获取下一个序列值
public int getNextNum() {
seqNum.set(seqNum.get() + 1);
return seqNum.get();
}
public static void main(String[] args) {
TestNum sn = new TestNum();
// ③ 3个线程共享sn,各自产生序列号
TestClient t1 = new TestClient(sn);
TestClient t2 = new TestClient(sn);
TestClient t3 = new TestClient(sn);
t1.start();
t2.start();
t3.start();
}
private static class TestClient extends Thread {
private TestNum sn;
public TestClient(TestNum sn) {
this.sn = sn;
}
public void run() {
for (int i = 0; i < 3; i++) {
// ④每个线程打出3个序列值
System.out.println("thread[" + Thread.currentThread().getName() + "] --> sn["
+ sn.getNextNum() + "]");
}
}
}
}
我々は、①に示す例のように、初期変数値を提供THREADLOCAL方法匿名の内部クラスで一般サブクラスを定義します。スレッドTestClientシーケンス番号のセットを生成する、③で、我々は3 TestClientを生成し、それらは同じTestNumインスタンスを共有します。コンソールに次の出力結果は、上記のコードを実行します:
スレッド[スレッド0] - > SN [1]
スレッド[スレッド-1] - > SN [1]
スレッド[スレッド-2] - > SN [1]
スレッド[スレッド-1] - > SN [ 2]
スレッド[スレッド0] - > SN [2]
スレッド[スレッド-1] - > SN [3]
スレッド[スレッド-2] - > SN [2]
スレッド[スレッド0] - > SN [3]
スレッド[スレッド-2] - > SN [3]
検査結果情報の出力は、我々は、各スレッドのIDが共有同じTestNum例発生するが、にもかかわらず彼らは、干渉が発生することがない、むしろ、それぞれ独立して生成されたシーケンス番号が、これは我々ので、各ThreadLocalのを通してであることがわかっスレッドは、独立したコピーを提供します。
概要
ThreadLocalのスレッドの安全性の問題は、それは変数の各コピーのために別のスレッドを提供することにより、変数の同時アクセスの競合の問題を解決し、非常に良いを解決する方法です。多くの場合、ThreadLocalのアドレスセキュリティのシンプルな、より便利な問題、およびプログラムの結果に同期スレッド同期メカニズムを使用するよりも高い並行性を持っています。