目次
ThreadLocal 関連クラス図
get
次は、
、null キーを使用してこれらのエントリの値にアクセスする方法はありません。
ホームページ Java &#&チュートリアル Java ThreadLocalクラスの使い方

Java ThreadLocalクラスの使い方

May 14, 2023 pm 06:49 PM
java threadlocal

    #図に示すように:

    Java ThreadLocalクラスの使い方#クイック スタート

    次に、簡単な例を使用して、ThreadLocal の基本的な使用法を示します。

    package cuit.pymjl.thradlocal;
    
    /**
     * @author Pymjl
     * @version 1.0
     * @date 2022/7/1 10:56
     **/
    public class MainTest {
        static ThreadLocal<String> threadLocal = new ThreadLocal<>();
    
        static void print(String str) {
            //打印当前线程中本地内存中本地变量的值
            System.out.println(str + " :" + threadLocal.get());
            //清除本地内存中的本地变量
            threadLocal.remove();
        }
    
        public static void main(String[] args) {
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    //设置线程1中本地变量的值
                    threadLocal.set("thread1 local variable");
                    //调用打印方法
                    print("thread1");
                    //打印本地变量
                    System.out.println("after remove : " + threadLocal.get());
                }
            });
    
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    //设置线程1中本地变量的值
                    threadLocal.set("thread2 local variable");
                    //调用打印方法
                    print("thread2");
                    //打印本地变量
                    System.out.println("after remove : " + threadLocal.get());
                }
            });
    
            t1.start();
            t2.start();
        }
    }
    ログイン後にコピー

    実行結果は、図に示すとおりです。

    Java ThreadLocalクラスの使い方ThreadLocal の原理

    ThreadLocal 関連クラス図

    まず、次に示すように、ThreadLocal 関連クラスのクラス図構造を見てみましょう。

    Java ThreadLocalクラスの使い方 この図からわかるように、Thread クラスには threadLocals と継承可能なThreadLocals があり、どちらも ThreadLocalMap 型の変数です。 、ThreadLocalMap はカスタマイズされたハッシュマップです。デフォルトでは、各スレッドのこれら 2 つの変数は null であり、現在のスレッドが初めて ThreadLocal の set メソッドまたは get メソッドを呼び出したときにのみ作成されます。実際、各スレッドのローカル変数は ThreadLocal インスタンスではなく、呼び出しスレッドの threadLocals 変数に格納されます。つまり、ThreadLocal 型のローカル変数は、特定のスレッド メモリ空間に格納されます。 ThreadLocal は、set メソッドを通じて呼び出しスレッドの threadLocals に値を入れて保存するツール シェルです。呼び出しスレッドが get メソッドを呼び出すと、現在のスレッドの threadLocals 変数から値を取り出して使用します。呼び出しスレッドが終了しない場合、このローカル変数は常に呼び出しスレッドの threadLocals 変数に格納されます。したがって、ローカル変数が必要ないときは、次のコマンドを呼び出して、現在のスレッドの threadLocals からローカル変数を削除できます。 ThreadLocal 変数のメソッドを削除します。さらに、Thread の threadLocals がマップ構造として設計されているのはなぜですか?各スレッドを複数の ThreadLocal 変数に関連付けることができるため、これは明らかです。次に、ThreadLocal の set、get、remove のソース コードを見てみましょう。

    set

        public void set(T value) {
            // 1.获取当前线程(调用者线程)
            Thread t = Thread.currentThread();
            // 2.以当前线程作为key值,去查找对应的线程变量,找到对应的map
            ThreadLocalMap map = getMap(t);
            if (map != null) {
                // 3.如果map不为null,则直接添加元素
                map.set(this, value);
            } else {
                // 4.否则就先创建map,再添加元素
                createMap(t, value);
            }
        }
    ログイン後にコピー
        void createMap(Thread t, T firstValue) {
            /**
             * 这里是创建一个ThreadLocalMap,以当前调用线程的实例对象为key,初始值为value
             * 然后放入当前线程的Therad.threadLocals属性里面
             */
            t.threadLocals = new ThreadLocalMap(this, firstValue);
        }
    ログイン後にコピー
        ThreadLocalMap getMap(Thread t) {
            //这里就是直接获取调用线程的成员属性threadlocals
            return t.threadLocals;
        }
    ログイン後にコピー

    get

        public T get() {
            // 1.获取当前线程
            Thread t = Thread.currentThread();
            // 2.获取当前线程的threadlocals,即ThreadLocalMap
            ThreadLocalMap map = getMap(t);
            // 3.如果map不为null,则直接返回对应的值
            if (map != null) {
                ThreadLocalMap.Entry e = map.getEntry(this);
                if (e != null) {
                    @SuppressWarnings("unchecked")
                    T result = (T)e.value;
                    return result;
                }
            }
            // 4.否则,则进行初始化
            return setInitialValue();
        }
    ログイン後にコピー

    次は、

    setInitialValue のコードです。

    ##

    private T setInitialValue() {
        //初始化属性,其实就是null
        T value = initialValue();
        //获取当前线程
        Thread t = Thread.currentThread();
        //通过当前线程获取ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        //如果map不为null,则直接添加元素
        if (map != null) {
            map.set(this, value);
        } else {
            //否则就创建,然后将创建好的map放入当前线程的属性threadlocals
            createMap(t, value);
        }
            //将当前ThreadLocal实例注册进TerminatingThreadLocal类里面
        if (this instanceof TerminatingThreadLocal) {
            TerminatingThreadLocal.register((TerminatingThreadLocal<?>) this);
        }
        return value;
    }
    ログイン後にコピー
    ここでいくつか説明を追加する必要がありますTerinatedThreadLocal

    。このクラスは jdk11 で新しく追加されたもので、jdk8 には存在しないため、インターネット上の多くのソース コード分析ではこのクラスに関連する説明がありません。このクラスのソース コードを確認したところ、その機能は ThreadLocal メモリ リークの問題を回避することになっているはずです (興味があれば、ソース コードを見て、間違いがあれば修正してください) )。これが公式の説明です:

    /**
     * A thread-local variable that is notified when a thread terminates and
     * it has been initialized in the terminating thread (even if it was
     * initialized with a null value).
     * 一个线程局部变量,
     * 当一个线程终止并且它已经在终止线程中被初始化时被通知(即使它被初始化为一个空值)。
     */
    ログイン後にコピー
    remove
         public void remove() {
             //如果当前线程的threadLocals 变量不为空, 则删除当前线程中指定ThreadLocal 实例的本地变量。
             ThreadLocalMap m = getMap(Thread.currentThread());
             if (m != null) {
                 m.remove(this);
             }
         }
    ログイン後にコピー

    summary

    各スレッド内には、threadLocals という名前のメンバー変数があります。この変数の型はハッシュ マップです。ここで、キーはは定義した ThreadLocal 変数の this 参照であり、value は set メソッドを使用して設定した値です。各スレッドのローカル変数は、スレッド自身のメモリ変数 threadLocals に格納されます。現在のスレッドが終了しない場合、これらのローカル変数は常に存在するため、メモリ オーバーフローが発生する可能性があります。したがって、削除後に ThreadLocal の Remove メソッドを呼び出すことを忘れないでください。スレッドに対応する threadLocals のローカル変数。

    ThreadLocal メモリ リーク

    メモリ リークはなぜ発生するのでしょうか?

    ThreadLocalMap は、ThreadLocal の弱参照をキーとして使用します。ThreadLocal がそれを参照するための外部強参照を持たない場合、ThreadLocal はシステム GC 中に必然的にリサイクルされます。 、ThreadLocalMap は、null キーを持つエントリが表示された場合、

    、null キーを使用してこれらのエントリの値にアクセスする方法はありません。

    現在のスレッドが長時間終了しない場合、常に存在します。参照チェーン: Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value は決してリサイクルできず、メモリ リークが発生します。

    実際、この状況は ThreadLocalMap の設計で考慮されており、いくつかの保護措置が追加されています。スレッド ThreadLocalMap 内の null であるすべてのキーは、get()、set()、および Remove の実行中にクリアされます。 ThreadLocal.値の()。ただし、これらの受動的な予防策では、メモリ リークが発生しないことを保証できません。静的 ThreadLocal を使用すると、ThreadLocal のライフ サイクルが延長され、メモリ リークが発生する可能性があります。

    • 割り当てでは ThreadLocal が使用され、メモリ リークにつながる get()、set()、remove() メソッドは呼び出されなくなりました。

    • 弱参照を使用する理由

    • 弱い参照を使用すると ThreadLocalMap のメモリ リークが発生することは誰もが知っているのに、なぜ当局は依然として強参照ではなく弱い参照を使用するのでしょうか?これは、弱参照と強参照の使用の違いから始まります。
    • 強参照を使用する場合: ThreadLocalMap のライフ サイクルは基本的に Thread のライフ サイクルと同じであることがわかっています。現在のスレッドが終了しない場合、ThreadLocalMap は GC によってリサイクルされません。と ThreadLocalMap が ThreadLocal の権利を保持します。強い参照を行うと、ThreadLocal はリサイクルされません。スレッドのライフサイクルが長い場合、手動で削除しないと kv が蓄積され、OOM

    • # が発生します。
    • ##弱い参照を使用する場合: 弱い 参照内のオブジェクトの宣言期間は短いです。これは、システム GC 中に、弱い参照が見つかった限り、ヒープ領域が残っているかどうかに関係なく、オブジェクトがリサイクルされるためです。十分な。 ThreadLocal の強参照を再利用すると、ThreadLocalMap が保持する弱参照も再利用されるため、手動で kv を削除しないと値が蓄積され、OOM

    比較より、弱参照を使用すると、少なくともマップ キーの蓄積によって OOM が発生しないことが保証され、対応する値は次の呼び出し時に、remove、get、set メソッドを通じてクリアできることがわかります。メモリ リークの根本原因は弱参照ではなく、ThreadLocalMap のライフ サイクルが Thread と同じくらい長いため、蓄積が発生していることがわかります。 OOM を引き起こす値の蓄積です。その後、適切な治療法を講じ、ThreadLocal を使用してクリーンアップするたびに

    remove()

    メソッドを呼び出します。

    以上がJava ThreadLocalクラスの使い方の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    このウェブサイトの声明
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

    ホットAIツール

    Undresser.AI Undress

    Undresser.AI Undress

    リアルなヌード写真を作成する AI 搭載アプリ

    AI Clothes Remover

    AI Clothes Remover

    写真から衣服を削除するオンライン AI ツール。

    Undress AI Tool

    Undress AI Tool

    脱衣画像を無料で

    Clothoff.io

    Clothoff.io

    AI衣類リムーバー

    AI Hentai Generator

    AI Hentai Generator

    AIヘンタイを無料で生成します。

    ホットツール

    メモ帳++7.3.1

    メモ帳++7.3.1

    使いやすく無料のコードエディター

    SublimeText3 中国語版

    SublimeText3 中国語版

    中国語版、とても使いやすい

    ゼンドスタジオ 13.0.1

    ゼンドスタジオ 13.0.1

    強力な PHP 統合開発環境

    ドリームウィーバー CS6

    ドリームウィーバー CS6

    ビジュアル Web 開発ツール

    SublimeText3 Mac版

    SublimeText3 Mac版

    神レベルのコード編集ソフト(SublimeText3)

    Javaの完全数 Javaの完全数 Aug 30, 2024 pm 04:28 PM

    Java における完全数のガイド。ここでは、定義、Java で完全数を確認する方法、コード実装の例について説明します。

    Java の乱数ジェネレーター Java の乱数ジェネレーター Aug 30, 2024 pm 04:27 PM

    Java の乱数ジェネレーターのガイド。ここでは、Java の関数について例を挙げて説明し、2 つの異なるジェネレーターについて例を挙げて説明します。

    ジャワのウェカ ジャワのウェカ Aug 30, 2024 pm 04:28 PM

    Java の Weka へのガイド。ここでは、weka java の概要、使い方、プラットフォームの種類、利点について例を交えて説明します。

    Javaのスミス番号 Javaのスミス番号 Aug 30, 2024 pm 04:28 PM

    Java のスミス番号のガイド。ここでは定義、Java でスミス番号を確認する方法について説明します。コード実装の例。

    Java Springのインタビューの質問 Java Springのインタビューの質問 Aug 30, 2024 pm 04:29 PM

    この記事では、Java Spring の面接で最もよく聞かれる質問とその詳細な回答をまとめました。面接を突破できるように。

    Java 8 Stream Foreachから休憩または戻ってきますか? Java 8 Stream Foreachから休憩または戻ってきますか? Feb 07, 2025 pm 12:09 PM

    Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

    Java での日付までのタイムスタンプ Java での日付までのタイムスタンプ Aug 30, 2024 pm 04:28 PM

    Java での日付までのタイムスタンプに関するガイド。ここでは、Java でタイムスタンプを日付に変換する方法とその概要について、例とともに説明します。

    未来を創る: まったくの初心者のための Java プログラミング 未来を創る: まったくの初心者のための Java プログラミング Oct 13, 2024 pm 01:32 PM

    Java は、初心者と経験豊富な開発者の両方が学習できる人気のあるプログラミング言語です。このチュートリアルは基本的な概念から始まり、高度なトピックに進みます。 Java Development Kit をインストールしたら、簡単な「Hello, World!」プログラムを作成してプログラミングを練習できます。コードを理解したら、コマンド プロンプトを使用してプログラムをコンパイルして実行すると、コンソールに「Hello, World!」と出力されます。 Java の学習はプログラミングの旅の始まりであり、習熟が深まるにつれて、より複雑なアプリケーションを作成できるようになります。

    See all articles