Jadual Kandungan
Permulaan Pantas
Prinsip ThreadLocal
Rajah kelas berkaitan ThreadLocal
set
get
alih keluar
Ringkasan
Kebocoran memori ThreadLocal
Mengapa kebocoran memori berlaku?
Rumah Java javaTutorial Bagaimana untuk menggunakan kelas Java ThreadLocal

Bagaimana untuk menggunakan kelas Java ThreadLocal

May 14, 2023 pm 06:49 PM
java threadlocal

    Seperti yang ditunjukkan dalam gambar:

    Bagaimana untuk menggunakan kelas Java ThreadLocal

    Permulaan Pantas

    Seterusnya, kami akan menggunakan contoh mudah untuk menunjukkan kepada anda penggunaan asas 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();
        }
    }
    Salin selepas log masuk

    Hasil larian adalah seperti yang ditunjukkan dalam rajah:

    Bagaimana untuk menggunakan kelas Java ThreadLocal

    Prinsip ThreadLocal

    Rajah kelas berkaitan ThreadLocal

    Mari kita lihat dahulu struktur gambar rajah kelas kelas berkaitan ThreadLocal, sebagai ditunjukkan dalam rajah:

    Bagaimana untuk menggunakan kelas Java ThreadLocal

    Seperti yang dapat dilihat daripada rajah ini, terdapat threadLocals dan inheritableThreadLocals dalam kelas ThreadLocalMap jenis, dan ThreadLocalMap ialah Hashmap tersuai. Secara lalai, kedua-dua pembolehubah ini dalam setiap utas adalah batal, dan ia dicipta hanya apabila utas semasa memanggil set atau dapatkan kaedah ThreadLocal untuk kali pertama. Sebenarnya, pembolehubah tempatan setiap utas tidak disimpan dalam contoh ThreadLocal, tetapi dalam pembolehubah threadLocals bagi utas panggilan. Dalam erti kata lain, pembolehubah tempatan jenis ThreadLocal disimpan dalam ruang memori benang tertentu. ThreadLocal ialah cangkerang alat yang meletakkan nilai ke dalam threadLocals pada utas panggilan melalui kaedah yang ditetapkan dan menyimpannya Apabila utas panggilan memanggil kaedah getnya, ia mengeluarkannya daripada pembolehubah threadLocals bagi utas semasa untuk digunakan. Jika utas panggilan tidak pernah ditamatkan, maka pembolehubah tempatan ini akan sentiasa disimpan dalam pembolehubah threadLocals bagi utas panggilan Oleh itu, apabila pembolehubah tempatan tidak diperlukan, anda boleh memadamkan pembolehubah tempatan daripada threadLocals bagi utas semasa dengan memanggil pembolehubah tempatan. alih keluar kaedah pembolehubah ThreadLocal. Selain itu, mengapakah threadLocals dalam Thread direka sebagai struktur peta? Jelas sekali kerana setiap utas boleh dikaitkan dengan berbilang pembolehubah ThreadLocal. Seterusnya, mari kita lihat kod sumber set ThreadLocal, dapatkan dan alih keluar

    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);
            }
        }
    Salin selepas log masuk
        void createMap(Thread t, T firstValue) {
            /**
             * 这里是创建一个ThreadLocalMap,以当前调用线程的实例对象为key,初始值为value
             * 然后放入当前线程的Therad.threadLocals属性里面
             */
            t.threadLocals = new ThreadLocalMap(this, firstValue);
        }
    Salin selepas log masuk
        ThreadLocalMap getMap(Thread t) {
            //这里就是直接获取调用线程的成员属性threadlocals
            return t.threadLocals;
        }
    Salin selepas log masuk

    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();
        }
    Salin selepas log masuk

    Berikut ialah kod 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;
    }
    Salin selepas log masuk

    Saya perlu menambah beberapa penjelasan tambahan di siniTerminatingThreadLocal. Kelas ini baharu dalam jdk11 dan tidak wujud dalam jdk8, jadi tiada perihalan berkaitan kelas ini dalam banyak analisis kod sumber di Internet. Saya telah melihat kod sumber kelas ini, dan fungsinya adalah untuk mengelakkan masalah kebocoran memori ThreadLocal (jika anda berminat, anda boleh menyemak kod sumber, dan sila betulkan saya jika terdapat sebarang ralat). Ini ialah penjelasan rasmi:

    /**
     * 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).
     * 一个线程局部变量,
     * 当一个线程终止并且它已经在终止线程中被初始化时被通知(即使它被初始化为一个空值)。
     */
    Salin selepas log masuk

    alih keluar

         public void remove() {
             //如果当前线程的threadLocals 变量不为空, 则删除当前线程中指定ThreadLocal 实例的本地变量。
             ThreadLocalMap m = getMap(Thread.currentThread());
             if (m != null) {
                 m.remove(this);
             }
         }
    Salin selepas log masuk

    Ringkasan

    Di dalam setiap utas, terdapat pembolehubah ahli bernama threadLocals, yang jenis Hash Map, dengan kuncinya rujukan ini bagi pembolehubah ThreadLocal yang kami takrifkan, dan nilai ialah nilai yang kami tetapkan menggunakan kaedah yang ditetapkan. Pembolehubah tempatan bagi setiap utas disimpan dalam utas pembolehubah memori sendiri. Jika utas semasa tidak pernah mati, pembolehubah tempatan ini akan sentiasa wujud, jadi ia boleh menyebabkan limpahan memori Oleh itu, ingat untuk memanggil kaedah alih keluar ThreadLocal untuk memadam gunakan. Pembolehubah setempat dalam threadLocals yang sepadan dengan thread.

    Kebocoran memori ThreadLocal

    Mengapa kebocoran memori berlaku?

    ThreadLocalMap menggunakan rujukan ThreadLocal yang lemah sebagai kunci Jika ThreadLocal tidak mempunyai rujukan kuat luaran untuk merujuk kepadanya, maka ThreadLocal pasti akan dikitar semula semasa GC sistem , ThreadLocalMap akan Apabila Entri dengan kekunci null muncul , tiada cara untuk mengakses nilai Entri ini dengan kekunci null Jika urutan semasa tidak berakhir untuk masa yang lama, akan sentiasa ada menjadi garis yang kuat untuk nilai Entri ini dengan kunci null: Rujukan Benang -> Sebenarnya, keadaan ini telah diambil kira dalam reka bentuk ThreadLocalMap, dan beberapa langkah perlindungan telah ditambah: semua kekunci dalam thread ThreadLocalMap yang batal akan dikosongkan semasa get(), set(), dan alih keluar () daripada nilai ThreadLocal. Walau bagaimanapun, langkah pencegahan pasif ini tidak dapat menjamin bahawa tiada kebocoran ingatan akan berlaku:

    • Menggunakan ThreadLocal statik memanjangkan kitaran hayat ThreadLocal, yang boleh menyebabkan kebocoran memori

    • Peruntukan menggunakan ThreadLocal dan tidak lagi memanggil kaedah get(), set(), remove(), yang akan membawa kepada kebocoran memori

    Mengapa menggunakan rujukan yang lemah?

    Memandangkan kita semua tahu bahawa menggunakan rujukan yang lemah akan menyebabkan kebocoran memori ThreadLocalMap, mengapakah pegawai masih menggunakan rujukan yang lemah dan bukannya rujukan yang kuat? Ini bermula dengan perbezaan antara menggunakan rujukan lemah dan rujukan kuat:

    • Jika anda menggunakan rujukan yang kukuh: Kami tahu bahawa kitaran hayat ThreadLocalMap pada asasnya adalah sama dengan kitaran hayat Thread Jika utas semasa tidak ditamatkan, maka ThreadLocalMap tidak akan dikitar semula oleh GC , dan ThreadLocalMap memegang hak untuk rujukan ThreadLocal Strong, maka ThreadLocal tidak akan dikitar semula Apabila kitaran hayat benang panjang, jika ia tidak dipadamkan secara manual, ia akan menyebabkan pengumpulan kv, mengakibatkan OOM

    • Jika anda menggunakan rujukan lemah: lemah Objek dalam rujukan mempunyai tempoh pengisytiharan yang sangat singkat, kerana semasa sistem GC, selagi rujukan lemah ditemui, objek akan dikitar semula tanpa mengira sama ada ruang timbunan berada mencukupi. Apabila rujukan kukuh ThreadLocal dikitar semula, rujukan lemah yang dipegang oleh ThreadLocalMap juga akan dikitar semula Jika kv tidak dipadamkan secara manual, ia akan menyebabkan pengumpulan nilai dan juga membawa kepada OOM

    Dari. perbandingan, kita dapat melihat bahawa menggunakan rujukan yang lemah sekurang-kurangnya dapat memastikan bahawa OOM tidak akan disebabkan oleh pengumpulan kunci peta, dan nilai yang sepadan boleh dikosongkan pada panggilan seterusnya melalui kaedah alih keluar, dapatkan dan tetapkan. Ia boleh dilihat bahawa punca kebocoran memori bukanlah rujukan yang lemah, tetapi kitaran hayat ThreadLocalMap adalah sepanjang Thread, menyebabkan pengumpulan

    Penyelesaian

    Memandangkan punca masalah adalah pengumpulan nilai yang menyebabkan OOM, Kemudian kami mengambil ubat yang betul dan hanya memanggil kaedah

    ThreadLocal untuk membersihkannya selepas setiap penggunaan. remove()

    Atas ialah kandungan terperinci Bagaimana untuk menggunakan kelas Java ThreadLocal. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

    Kenyataan Laman Web ini
    Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

    Alat AI Hot

    Undresser.AI Undress

    Undresser.AI Undress

    Apl berkuasa AI untuk mencipta foto bogel yang realistik

    AI Clothes Remover

    AI Clothes Remover

    Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

    Undress AI Tool

    Undress AI Tool

    Gambar buka pakaian secara percuma

    Clothoff.io

    Clothoff.io

    Penyingkiran pakaian AI

    Video Face Swap

    Video Face Swap

    Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

    Alat panas

    Notepad++7.3.1

    Notepad++7.3.1

    Editor kod yang mudah digunakan dan percuma

    SublimeText3 versi Cina

    SublimeText3 versi Cina

    Versi Cina, sangat mudah digunakan

    Hantar Studio 13.0.1

    Hantar Studio 13.0.1

    Persekitaran pembangunan bersepadu PHP yang berkuasa

    Dreamweaver CS6

    Dreamweaver CS6

    Alat pembangunan web visual

    SublimeText3 versi Mac

    SublimeText3 versi Mac

    Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

    Topik panas

    Tutorial Java
    1663
    14
    Tutorial PHP
    1266
    29
    Tutorial C#
    1239
    24
    Cuti atau kembali dari Java 8 Stream Foreach? Cuti atau kembali dari Java 8 Stream Foreach? Feb 07, 2025 pm 12:09 PM

    Java 8 memperkenalkan API Stream, menyediakan cara yang kuat dan ekspresif untuk memproses koleksi data. Walau bagaimanapun, soalan biasa apabila menggunakan aliran adalah: bagaimana untuk memecahkan atau kembali dari operasi foreach? Gelung tradisional membolehkan gangguan awal atau pulangan, tetapi kaedah Foreach Stream tidak menyokong secara langsung kaedah ini. Artikel ini akan menerangkan sebab -sebab dan meneroka kaedah alternatif untuk melaksanakan penamatan pramatang dalam sistem pemprosesan aliran. Bacaan Lanjut: Penambahbaikan API Java Stream Memahami aliran aliran Kaedah Foreach adalah operasi terminal yang melakukan satu operasi pada setiap elemen dalam aliran. Niat reka bentuknya adalah

    PHP: Bahasa utama untuk pembangunan web PHP: Bahasa utama untuk pembangunan web Apr 13, 2025 am 12:08 AM

    PHP adalah bahasa skrip yang digunakan secara meluas di sisi pelayan, terutamanya sesuai untuk pembangunan web. 1.PHP boleh membenamkan HTML, memproses permintaan dan respons HTTP, dan menyokong pelbagai pangkalan data. 2.PHP digunakan untuk menjana kandungan web dinamik, data borang proses, pangkalan data akses, dan lain -lain, dengan sokongan komuniti yang kuat dan sumber sumber terbuka. 3. PHP adalah bahasa yang ditafsirkan, dan proses pelaksanaan termasuk analisis leksikal, analisis tatabahasa, penyusunan dan pelaksanaan. 4.Php boleh digabungkan dengan MySQL untuk aplikasi lanjutan seperti sistem pendaftaran pengguna. 5. Apabila debugging php, anda boleh menggunakan fungsi seperti error_reporting () dan var_dump (). 6. Mengoptimumkan kod PHP untuk menggunakan mekanisme caching, mengoptimumkan pertanyaan pangkalan data dan menggunakan fungsi terbina dalam. 7

    PHP vs Python: Memahami Perbezaan PHP vs Python: Memahami Perbezaan Apr 11, 2025 am 12:15 AM

    PHP dan Python masing -masing mempunyai kelebihan sendiri, dan pilihannya harus berdasarkan keperluan projek. 1.Php sesuai untuk pembangunan web, dengan sintaks mudah dan kecekapan pelaksanaan yang tinggi. 2. Python sesuai untuk sains data dan pembelajaran mesin, dengan sintaks ringkas dan perpustakaan yang kaya.

    PHP vs Bahasa Lain: Perbandingan PHP vs Bahasa Lain: Perbandingan Apr 13, 2025 am 12:19 AM

    PHP sesuai untuk pembangunan web, terutamanya dalam pembangunan pesat dan memproses kandungan dinamik, tetapi tidak baik pada sains data dan aplikasi peringkat perusahaan. Berbanding dengan Python, PHP mempunyai lebih banyak kelebihan dalam pembangunan web, tetapi tidak sebaik python dalam bidang sains data; Berbanding dengan Java, PHP melakukan lebih buruk dalam aplikasi peringkat perusahaan, tetapi lebih fleksibel dalam pembangunan web; Berbanding dengan JavaScript, PHP lebih ringkas dalam pembangunan back-end, tetapi tidak sebaik JavaScript dalam pembangunan front-end.

    PHP vs Python: Ciri dan Fungsi Teras PHP vs Python: Ciri dan Fungsi Teras Apr 13, 2025 am 12:16 AM

    PHP dan Python masing -masing mempunyai kelebihan sendiri dan sesuai untuk senario yang berbeza. 1.PHP sesuai untuk pembangunan web dan menyediakan pelayan web terbina dalam dan perpustakaan fungsi yang kaya. 2. Python sesuai untuk sains data dan pembelajaran mesin, dengan sintaks ringkas dan perpustakaan standard yang kuat. Apabila memilih, ia harus diputuskan berdasarkan keperluan projek.

    Program Java untuk mencari kelantangan kapsul Program Java untuk mencari kelantangan kapsul Feb 07, 2025 am 11:37 AM

    Kapsul adalah angka geometri tiga dimensi, terdiri daripada silinder dan hemisfera di kedua-dua hujungnya. Jumlah kapsul boleh dikira dengan menambahkan isipadu silinder dan jumlah hemisfera di kedua -dua hujungnya. Tutorial ini akan membincangkan cara mengira jumlah kapsul yang diberikan dalam Java menggunakan kaedah yang berbeza. Formula volum kapsul Formula untuk jumlah kapsul adalah seperti berikut: Kelantangan kapsul = isipadu isipadu silinder Dua jumlah hemisfera dalam, R: Radius hemisfera. H: Ketinggian silinder (tidak termasuk hemisfera). Contoh 1 masukkan Jejari = 5 unit Ketinggian = 10 unit Output Jilid = 1570.8 Unit padu menjelaskan Kirakan kelantangan menggunakan formula: Kelantangan = π × r2 × h (4

    Impak PHP: Pembangunan Web dan seterusnya Impak PHP: Pembangunan Web dan seterusnya Apr 18, 2025 am 12:10 AM

    Phphassignificantelympactedwebdevelopmentandextendsbeyondit.1) itpowersmajorplatformslikeworderpressandexcelsindatabaseIntions.2) php'SadaptabilityAldoStoScaleforlargeapplicationFrameworksLikelara.3)

    PHP: asas banyak laman web PHP: asas banyak laman web Apr 13, 2025 am 12:07 AM

    Sebab mengapa PHP adalah timbunan teknologi pilihan untuk banyak laman web termasuk kemudahan penggunaannya, sokongan komuniti yang kuat, dan penggunaan yang meluas. 1) Mudah dipelajari dan digunakan, sesuai untuk pemula. 2) Mempunyai komuniti pemaju yang besar dan sumber yang kaya. 3) Digunakan secara meluas dalam platform WordPress, Drupal dan lain -lain. 4) Mengintegrasikan dengan ketat dengan pelayan web untuk memudahkan penggunaan pembangunan.

    See all articles