ThreadLocalの=ネイティブスレッド?

まず、定義

ThreadLocalそれはJDK、ビューの名前から、パッケージ提供ThreadLocalの意味のローカルスレッドを意味します。

何1.1?

彼はGeshaある知るために、我々は見てThreadLocal(に基づいてソースコードJDK 1.8)は、このクラスの導入:

This class provides thread-local variables.  These variables differ from
their normal counterparts in that each thread that accesses one (via its
{@code get} or {@code set} method) has its own, independently initialized
copy of the variable.  {@code ThreadLocal} instances are typically private
static fields in classes that wish to associate state with a thread (e.g.,
a user ID or Transaction ID).

それは大体まとめることができます。

  1. TreadLocalお互いを乱すことなく、私たちは私たちに、スレッド内のローカル変数を提供することができ、かつ、この変数と変数の一般的にも異なる、それは各スレッドに固有であり、他のスレッド。
  2. ThreadLocal通常の変数の違いは:各スレッドは変数にコピーの完全に別個のインスタンスを初期化するために使用します。ThreadLocal変数は通常されているprivate static修正します。スレッドの終了時に、すべてのそれは使用していますThreadLocal比較的インスタンスのコピーが回復されます。
  3. それは単にThreadLocal、すべての中で、時間のための練習スペースの一種でThread維持するThreadLocal.ThreadLocalMapデータの分離は、スレッドごとのデータを共有していないが、セキュリティスレッドのない自然な問題はありません。

1.2例

コードをYiyanbuge!

//创建ThreadLocal变量
private static ThreadLocal<String> localParam = new ThreadLocal<>();

@Test
public void threadLocalDemo() {
    //创建2个线程,分别设置不同的值
    new Thread(() -> {
        localParam.set("Hello 风尘博客!");
        //打印当前线程本地内存中的localParam变量的值
        log.info("{}:{}", Thread.currentThread().getName(), localParam.get());
    }, "T1").start();
    new Thread(() -> {
        log.info("{}:{}", Thread.currentThread().getName(), localParam.get());
    }, "T2").start();
}
  • 結果:
... T1:Hello 风尘博客!
... T2:null

印刷結果はT1、スレッドの値が設定できないT2変数があることを証明してThreadLocal各スレッドでデータを共有することはありません。

1.3 ThreadLocalAPI

ThreadLocalこれは、4つのメソッドを定義しています。

  1. get():現在のこのスレッドローカルコピーの値を返します。
  2. set(T value):指定された値にスレッドローカル変数の現在のコピーの値。
  3. initialValue():現在の初期値のこのスレッドローカルコピーを返します。
  4. remove():このスレッドローカルの現在の除去の値のコピー。
  • set()そして、initialValue()の違い
名前 set() initialValue()
定義 このスレッドは、新しい値を設定しています この方法は、初期値を設定するために使用され、呼び出しがget()メソッドがそれほど遅延ロードされたときにトリガされます。しかし場合get()の前に行うset()そうではないよう呼びかけに、操作
違い オブジェクトは、我々がコントロールを使用するときのタイミングでない生成された場合set()のモードを オブジェクトは、当社の制御使用して初期化されるときのタイミングinitialValue()モードを

第二に、実現原理

ThreadLocal特に重要な静的な内部クラスがありThreadLocalMap、そのような分離のスレッドが実装の重要なメカニズムです。

  • 各スレッドローカル変数はに格納されていないThreadLocalインスタンスの内部が、呼び出し元のスレッドに保持threadLocals内部変数、すなわち:ThreadLocal特定のスレッドのメモリ空間に格納されているローカル変数のタイプ。
ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
  • Thread2つのがあり、クラスのあるThreadLocalMap変数の型は、それぞれthreadLocals、とinheritableThreadLocalsしながら、ThreadLocalMapカスタマイズされたHashmap、スレッドローカル変数を格納するために設計されています。デフォルトでは、これら二つの変数の各スレッドがありnull、現在のスレッドにのみ最初の呼び出し、または彼らが近づいたときに作成されます。ThreadLocalset()get()

ダストのブログ

  • ThreadLocalそれはによって工具ハウジング、あるset()メソッドvalueを呼び出すスレッドの値threadLocals内とそれが呼び出したスレッドを呼び出したときに、それを格納get()する方法、そして、現在のスレッドの中にthreadLocals使用に置かれる変数。

  • 呼び出し元のスレッドが終了していない場合、ローカル変数はいつもの呼び出し元のスレッドに保存されますthreadLocals必要が呼び出すことにより、ローカル変数を使用するには、変数ThreadLocalの変数をremove()現在のスレッド方式から、threadLocalsローカル変数の内部を削除します。

さらにThread内部はthreadLocalsとして設計されているMap各スレッドが複数に関連付けることができるので、構造ThreadLocal変数。

原理の概要

  1. それぞれがThread維持ThreadLocalMap参照。
  2. ThreadLocalMapThreadLocal使用、内部クラスEntryのストレージのためには、
  3. 调用ThreadLocalset()方法时,实际上就是往ThreadLocalMap设置值,keyThreadLocal对象,值是传递进来的对象;
  4. 调用ThreadLocalget()方法时,实际上就是往ThreadLocalMap获取值,keyThreadLocal对象;
  5. ThreadLocal本身并不存储值,它只是作为一个key来让线程从ThreadLocalMap获取value

三、使用场景

3.1 ThreadLocal的作用

  • 保存线程上下文信息,在任意需要的地方可以获取.

由于ThreadLocal的特性,同一线程在某地方进行设置,在随后的任意地方都可以获取到。从而可以用来保存线程上下文信息。

  • 线程安全的,避免某些情况需要考虑线程安全必须同步带来的性能损失.

3.2 场景一:独享对象

每个线程需要一个独享对象(通常是工具类,典型需要使用的类有SimpleDateFormatRandom

这类场景阿里规范里面也提到了:

ダストのブログ

3.3 场景二:当前信息需要被线程内的所有方法共享

每个线程内需要保存全局变量(例如在拦截器中获取用户信息),可以让不同方法直接使用,避免参数传递的麻烦。

演示(完整演示见文末Github

  • User.java
@Data
public class User {
    private String userName;

    public User() {

    }

    public User(String userName) {
        this.userName = userName;
    }
}
  • UserContextHolder.java
public class UserContextHolder {

    public static ThreadLocal<User> holder = new ThreadLocal<>();

}
  • Service1.java
public class Service1 {

    public void process() {
        User user = new User("Van");
        //将User对象存储到 holder 中
        UserContextHolder.holder.set(user);
        new Service2().process();
    }
}
  • Service2.java
public class Service2 {

    public void process() {
        User user = UserContextHolder.holder.get();
        System.out.println("Service2拿到用户名: " + user.getUserName());
        new Service3().process();
    }
}
  • Service3.java
public class Service3 {

    public void process() {
        User user = UserContextHolder.holder.get();
        System.out.println("Service3拿到用户名: " + user.getUserName());
    }
}
  • 测试方法
@Test
public void threadForParams() {
    new Service1().process();
}
  • 结果打印
Service2拿到用户名: Van
Service3拿到用户名: Van

3.4 使用ThreadLocal的好处

  1. 达到线程安全的目的;
  2. 不需要加锁,执行效率高;
  3. 更加节省内存,节省开销;
  4. 免去传参的繁琐,降低代码耦合度。

四、问题

4.1 内存泄漏问题

内存泄露:某个对象不会再被使用,但是该对象的内存却无法被收回

  • 正常情况

Thread运行结束后,ThreadLocal中的value会被回收,因为没有任何强引用了。

  • 非正常情况

Thread決して終わらない実行された、強力な参照は、コールチェーン以下、回復されることはありません

Thread-->ThreadLocalMap-->Entry(key为null)-->value

呼び出しチェーンなのでvalueThread強い参照が存在し、それがvalueリサイクルすることができない、発生する可能性がありますOOM

メモリリーク(アリ仕様)を回避する方法

呼び出しremove()方法を、それが対応する削除させていただきますEntryので、最大使用、メモリリークを回避するために、オブジェクトをThreadLocal呼び出すために、後remove()の方法を。

4.2 ThreadLocalNULLポインタの問題

  • ThreadLocalNPE.java
public class ThreadLocalNPE {

    ThreadLocal<Long> longThreadLocal = new ThreadLocal<>();

    public void set() {
        longThreadLocal.set(Thread.currentThread().getId());
    }

    /**
     * 当前返回值为基本类型,会报空指针异常,如果改成包装类型Long就不会出错
     * @return
     */
    public long get() {
        return longThreadLocal.get();
    }
}
  • NULLポインタテスト
@Test
public void threadLocalNPE() {
    ThreadLocalNPE threadLocalNPE = new ThreadLocalNPE();
    //如果get方法返回值为基本类型,则会报空指针异常,如果是包装类型就不会出错
    System.out.println(threadLocalNPE.get());
}

場合get()この方法は、基本的なタイプの値を返し、パケットヌル・ポインタ例外が発生し、エラーがパッケージタイプではない場合。私たちがでなければならないので、これは、プリミティブ型とパッケージタイプのボクシングとアンボクシングとの関係からですget()パッケージのメソッドの戻り値の型。

4.3参考記事

  1. THREADLOCAL学びません、もう1つは(言葉の要約を)忘れてしまうか見るん
  2. 慢性的な問題を解決するためにThreadLocalの時間を使用します

第四に、技術交流

Githubのサンプルコード

  1. ダストのブログます。https://www.dustyblog.cn
  2. ダストのブログ - デンバー
  3. ダストは、ブログ - ブログパーク
  4. Githubの

おすすめ

転載: www.cnblogs.com/vandusty/p/12194718.html