Java インタビューでの ThreadLocal の質問

ThreadLocal とは何ですか、またその基本的な使用方法は何ですか 

簡単に言うと、マルチスレッドで変数を独立させておくことができるスレッドオブジェクトです。

Threadlocal マルチスレッドを使用せずに同じ変数にアクセスしたときに発生する問題

package com.pxx;

/**
 * Created by Administrator on 2023/9/3.
 */
public class Demo1 {
    private String v1;

    public String getV1() {
        return v1;
    }

    public void setV1(String v1) {
        this.v1 = v1;
    }

    public static void main(String[] args) {
        //开启一个多线程去设置并且访问这个变量

        Demo1 d1 = new Demo1();
        //这里会循环五个线程
        for(int i = 0;i < 5;i++) {
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    //设置并且打印一个变量的数据
                    d1.setV1("data:" + Thread.currentThread().getName());
                    System.out.println("-------------");
                    //取出这个线程对应的名字和值
                    System.out.println(Thread.currentThread().getName() + "=>" + d1.getV1());
                }
            });

            //设置一下每一个线程的名字
            t1.setName("线程" + i);
            t1.start();//开启直接进入到运行状态,然后当前线程开始运行,然后进行下一次循环,下一个线程进来,这个时候进程可能会仙湖干扰
        }

    }
}

次のスレッドは直接混乱しています 

 一般的に言えば、同期を導入するなど、ロックを使用して問題を解決できます。ここでは最初にロックは必要ありません。解決するには ThreadLocal を使用します。

非同期スレッドの問題を解決する ThreadLocal クラス

その目的は、変数を独立した状態に保つことです。

一般的な方法を見てみましょう

set(): 変数を現在のスレッドにバインドします

get(): 現在のスレッドによってバインドされている変数を取得します

上記のコードを変更します

package com.pxx;

/**
 * Created by Administrator on 2023/9/3.
 */
public class Demo1 {
    //引入绑定变量的线程对象
    ThreadLocal<String>  tl1= new ThreadLocal();

    private String v1;

    public String getV1() {
       // return v1;
        return tl1.get();//得到通过set绑定的变量
    }

    public void setV1(String v1) {
        //this.v1 = v1;
        tl1.set(v1);//直接把这个v1绑定到对象里面
    }

    public static void main(String[] args) {

        Demo1 d1 = new Demo1();
        //这里会循环五个线程
        for(int i = 0;i < 5;i++) {
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    //设置并且打印一个变量的数据
                    d1.setV1("data:" + Thread.currentThread().getName());
                    System.out.println("-------------");
                    //取出这个线程对应的名字和值
                    System.out.println(Thread.currentThread().getName() + "=>" + d1.getV1());
                }
            });

            //设置一下每一个线程的名字
            t1.setName("线程" + i);
            t1.start();//开启直接进入到运行状态,然后当前线程开始运行,然后进行下一次循环,下一个线程进来,这个时候进程可能会仙湖干扰
        }
    }
}

操作結果:

 ThreadLocal と同期の違い

まず上記のコードを同期化してロックします。

package com.pxx;

/**
 * Created by Administrator on 2023/9/3.
 */
public class Demo3 {
    //引入绑定变量的线程对象
    ThreadLocal<String>  tl1 = new ThreadLocal();

    private String v1;

    public String getV1() {
        return v1;
    }

    public void setV1(String v1) {
        this.v1 = v1;
    }

    public static void main(String[] args) {

        Demo3 d1 = new Demo3();
        //这里会循环五个线程
        for(int i = 0;i < 5;i++) {
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (d1) {//这个加锁了
                        //设置并且打印一个变量的数据
                        d1.setV1("data:" + Thread.currentThread().getName());
                        System.out.println("-------------");
                        //取出这个线程对应的名字和值
                        System.out.println(Thread.currentThread().getName() + "=>" + d1.getV1());
                    }
                }
            });

            //设置一下每一个线程的名字
            t1.setName("线程" + i);
            t1.start();//开启直接进入到运行状态,然后当前线程开始运行,然后进行下一次循环,下一个线程进来,这个时候进程可能会仙湖干扰
        }
    }

}

操作結果:

明らかにロックされてる

これらの共通点について話しましょう。どちらも、複数のスレッドによる変数への同時アクセスの問題を扱っています。

同期: 教室にトイレが 1 つしかなく、全員が入って列に並ばなければならないのと同じように、スレッドがアクセスのためにキューに入れられていると同じなので、効率は低くなります。

ThreadLocal: 高効率。これは、スレッドが同時に同時にアクセスできることを意味します。高効率。教室内の複数のトイレのように、相互に接続されていますが、互いに独立しています。

ThreadLocalの内部構造

初期の設計原則の 1 つ

 JDK8の設計原理

JDK8はThreadの各スレッドをメインスレッドとみなし、EntryにThreadLocalなどのスレッドオブジェクトを格納することに注意してください。

このような設計スキームには 2 つの利点があります。

1. 各マップに格納されるエントリの数が減ります。これは、言い換えると、Thread スレッドが ThreadLocal スレッドよりも多くなければならないためです。

2.その後、メインスレッドThreadが破棄され、内部のマップデータオブジェクトも破棄されます

ソースコードを解析してみます

まずはsetメソッドを見てみましょう

ThreadLocalMap クラスをもう一度見てみましょう 

 

セットがマップオブジェクトに追加されます

これは問題の説明にはなりません。スレッドの同時アクセスと変数エラーの問題は解決されます。

なんと、お互いに影響を与えずに、一人でトイレに行くのです。

 メモリリークの問題を引き起こす可能性がある

彼はそれを 2 つのケースに分けて考えています。

最初のタイプ: メモリが十分ではない、オーバーフローのみ メモリ オーバーフロー

2 番目のタイプ: メモリ リーク メモリ リーク、ヒープ上の領域を解放できないため、無駄が発生し、プログラムの実行速度に影響を及ぼします。この無駄が多すぎると、メモリ オーバーフローが発生します。 

ここでさらに 2 つの概念を紹介します

1つ目: 強参照とは何ですか? 通常、オブジェクトを参照するときに、そのオブジェクトに意味がない場合、そのオブジェクトは gc によって削除されます。つまり、ガベージ コレクターがオブジェクトをリサイクルします。

2 番目: 弱い参照とは何ですか? つまり、GC に遭遇するとリサイクルされます。ガベージ コレクション メカニズムが実行されている限り、jvm のメモリ領域が十分であるかどうかに関係なく、オブジェクトによって占有されているメモリは再利用されます。

参照関係を次の図に示します。

キーが強参照の場合

ThreadLocal が使い果たされて参照が取り消され、Map 内の ThreadLocal が強参照であるため、ThreadLocal オブジェクトをリサイクルできないとします。

Entry クラスが手動で削除されず、CurrentThread がまだ実行されている場合、Entry クラスはまったくウェーブされず、メモリ リークが発生します。

キーが弱参照であると仮定すると、ThreadLocal 参照がなくなり、マップ内に ThreadLocal を指す弱参照が存在します。これは、ThreadLocal がガベージ コレクターによってすぐにリサイクルされることを意味します。 NULL になる場合は、値にアクセスできなくなり、値をリサイクルできないため、メモリ リークが発生します。

明らかにソースコードには弱い参照が与えられています

上記は、強参照または弱参照がメモリ リークを引き起こすことも示しています。

メモリ リークの根本原因は次のとおりです。

最初のポイント: Entry クラスは常にメモリ内に存在し、手動による削除はありません。

2 番目のポイント: CurrentThread スレッドがまだ実行中である

それでは、おはよう、こんにちは、おやすみをお祈りします。

Supongo que te gusta

Origin blog.csdn.net/Pxx520Tangtian/article/details/132651957
Recomendado
Clasificación