Jadual Kandungan
Pengenalan
1. Demonstrasi penggunaan
Rumah Java javaTutorial Penjelasan terperinci dan analisis kod sumber ThreadLocal dalam pengaturcaraan Java

Penjelasan terperinci dan analisis kod sumber ThreadLocal dalam pengaturcaraan Java

Apr 21, 2023 pm 03:19 PM
java threadlocal

    Pengenalan

    ThreadLocal menyediakan cara supaya dalam persekitaran berbilang benang, setiap utas boleh mempunyai data uniknya sendiri dan boleh Dilalui dari atas ke bawah sepanjang pelaksanaan benang.

    1. Demonstrasi penggunaan

    Ramai pelajar mungkin tidak pernah menggunakan ThreadLocal sebelum ini menjalankan keputusan, anda boleh Lihat, nilai yang sepadan dengan key1 telah diperoleh daripada konteks.

    /**
     * ThreadLocal 中保存的数据是 Map
     */
    static final ThreadLocal<Map<String, String>> context = new ThreadLocal<>();
    @Test
    public void testThread() {
      // 从上下文中拿出 Map
      Map<String, String> contextMap = context.get();
      if (CollectionUtils.isEmpty(contextMap)) {
        contextMap = Maps.newHashMap();
      }
      contextMap.put("key1", "value1");
      context.set(contextMap);
      log.info("key1,value1被放到上下文中");
    	// 从上下文中拿出刚才放进去的数据
      getFromComtext();
    }
    private String getFromComtext() {
      String value1 = context.get().get("key1");
      log.info("从 ThreadLocal 中取出上下文,key1 对应的值为:{}", value1);
      return value1;
    }
    //运行结果:
    demo.ninth.ThreadLocalDemo - key1,value1被放到上下文中
    demo.ninth.ThreadLocalDemo - 从 ThreadLocal 中取出上下文,key1 对应的值为:value1
    Salin selepas log masuk
    Kaedah getFromComtext tidak menerima sebarang parameter input Melalui baris kod ini, context.get().get(“key1”), nilai key1 diperoleh daripada konteks Seterusnya, mari ambil a lihat ThreadLocal. Bagaimana lapisan asas melaksanakan pemindahan konteks.

    2. Struktur kelas

    2.1. Generik kelas

    ThreadLocal mentakrifkan kelas dengan generik, menunjukkan bahawa ThreadLocal boleh menyimpan data dalam mana-mana format adalah seperti berikut:

    2.2. Atribut utama

    public class ThreadLocal<T> {}
    Salin selepas log masuk
    ThreadLocal mempunyai beberapa atribut utama Mari kita lihat satu persatu:

    Terdapat satu lagi atribut penting. : ThreadLocalMap, apabila thread Apabila terdapat berbilang ThreadLocals, bekas diperlukan untuk mengurus berbilang ThreadLocals Ini ialah peranan ThreadLocalMap, untuk mengurus berbilang ThreadLocals dalam thread.

    // threadLocalHashCode 表示当前 ThreadLocal 的 hashCode,用于计算当前 ThreadLocal 在 ThreadLocalMap 中的索引位置
    private final int threadLocalHashCode = nextHashCode();
    // 计算 ThreadLocal 的 hashCode 值(就是递增)
    private static int nextHashCode() {
        return nextHashCode.getAndAdd(HASH_INCREMENT);
    }
    // static + AtomicInteger 保证了在一台机器中每个 ThreadLocal 的 threadLocalHashCode 是唯一的
    // 被 static 修饰非常关键,因为一个线程在处理业务的过程中,ThreadLocalMap 是会被 set 多个 ThreadLocal 的,多个 ThreadLocal 就依靠 threadLocalHashCode 进行区分
    private static AtomicInteger nextHashCode = new AtomicInteger();
    Salin selepas log masuk
    Salin selepas log masuk
    2.2.1, ThreadLocalMap

    ThreadLocalMap itu sendiri ialah struktur Peta yang mudah, kuncinya ialah ThreadLocal, nilainya ialah nilai yang disimpan oleh ThreadLocal, lapisan bawah ialah struktur data tatasusunan, kod sumber adalah seperti berikut:

    Daripada kod sumber, kita dapat melihat bahawa ThreadLocalMap sebenarnya adalah struktur Peta yang mudah Lapisan bawah ialah tatasusunan, dengan saiz permulaan dan saiz ambang pengembangan. Elemen tatasusunan ialah Entry Kunci Entry ialah rujukan kepada ThreadLocal, dan nilainya ialah nilai ThreadLocal.

    // threadLocalHashCode 表示当前 ThreadLocal 的 hashCode,用于计算当前 ThreadLocal 在 ThreadLocalMap 中的索引位置
    private final int threadLocalHashCode = nextHashCode();
    // 计算 ThreadLocal 的 hashCode 值(就是递增)
    private static int nextHashCode() {
        return nextHashCode.getAndAdd(HASH_INCREMENT);
    }
    // static + AtomicInteger 保证了在一台机器中每个 ThreadLocal 的 threadLocalHashCode 是唯一的
    // 被 static 修饰非常关键,因为一个线程在处理业务的过程中,ThreadLocalMap 是会被 set 多个 ThreadLocal 的,多个 ThreadLocal 就依靠 threadLocalHashCode 进行区分
    private static AtomicInteger nextHashCode = new AtomicInteger();
    Salin selepas log masuk
    Salin selepas log masuk
    3. Bagaimanakah ThreadLocal mencapai pengasingan data antara utas

    ThreadLocal selamat untuk thread dan kami boleh menggunakannya dengan yakin, terutamanya kerana ThreadLocalMap ialah atribut bagi thread di thread Thread Kod sumber Eksklusif untuk pengasingan.

    Apabila urutan induk mencipta urutan anak, ia akan menyalin nilai inheritableThreadLocals, tetapi bukan nilai threadLocals Kod sumber adalah seperti berikut:

    Penjelasan terperinci dan analisis kod sumber ThreadLocal dalam pengaturcaraan Java<. 🎜>Dari atas Kita dapat melihat dalam rajah bahawa apabila thread dicipta, nilai atribut inheritableThreadLocals thread induk akan disalin.

    4. Kaedah tetapkan

    Fungsi utama kaedah set adalah untuk menetapkan nilai dalam ThreadLocal semasa Jika jenis generik ThreadLocal semasa ialah Map, maka ia adalah untuk menetapkan peta dalam ThreadLocal semasa Kod sumber adalah seperti berikut:

    Penjelasan terperinci dan analisis kod sumber ThreadLocal dalam pengaturcaraan JavaLogik kod agak jelas Mari kita lihat kod sumber ThreadLocalMap.set, seperti berikut:

    <🎜. >

    Kita harus memberi perhatian kepada beberapa perkara dalam kod sumber di atas:

    menggunakan AtomicInteger yang semakin meningkat sebagai Kod cincang ThreadLocal

    // set 操作每个线程都是串行的,不会有线程安全的问题
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        // 当前 thradLocal 之前有设置值,直接设置,否则初始化
        if (map != null)
            map.set(this, value);
        // 初始化ThreadLocalMap
        else
            createMap(t, value);
    }
    Salin selepas log masuk

    Rumus untuk mengira kedudukan indeks tatasusunan ialah: kod cincang modulo saiz tatasusunan, Oleh itu,Kod cincang yang berbeza kemungkinan besar akan mengira kedudukan indeks tatasusunan yang sama (tetapi jangan risau tentang perkara ini, dalam keadaan sebenar. projek, terdapat sangat sedikit ThreadLocals, dan pada dasarnya tiada konflik); untuk mencari ke belakang melalui +1 sehingga ia menemui kedudukan indeks kosong, dan meletakkan ThreadLocal semasa sebagai kunci.
    private void set(ThreadLocal<?> key, Object value) {
        Entry[] tab = table;
        int len = tab.length;
        // 计算 key 在数组中的下标,其实就是 ThreadLocal 的 hashCode 和数组大小-1取余
        int i = key.threadLocalHashCode & (len-1);
     
        // 整体策略:查看 i 索引位置有没有值,有值的话,索引位置 + 1,直到找到没有值的位置
        // 这种解决 hash 冲突的策略,也导致了其在 get 时查找策略有所不同,体现在 getEntryAfterMiss 中
        for (Entry e = tab[i];
             e != null;
             // nextIndex 就是让在不超过数组长度的基础上,把数组的索引位置 + 1
             e = tab[i = nextIndex(i, len)]) {
            ThreadLocal<?> k = e.get();
            // 找到内存地址一样的 ThreadLocal,直接替换
            if (k == key) {
                e.value = value;
                return;
            }
            // 当前 key 是 null,说明 ThreadLocal 被清理了,直接替换掉
            if (k == null) {
                replaceStaleEntry(key, value, i);
                return;
            }
        }
        // 当前 i 位置是无值的,可以被当前 thradLocal 使用
        tab[i] = new Entry(key, value);
        int sz = ++size;
        // 当数组大小大于等于扩容阈值(数组大小的三分之二)时,进行扩容
        if (!cleanSomeSlots(i, sz) && sz >= threshold)
            rehash();
    }
    Salin selepas log masuk

      Mujurlah, apabila menggunakan ThreadLocal dalam kerja harian, kami selalunya hanya menggunakan 1~2 ThreadLocal, dan kebarangkalian tatasusunan pendua yang dikira melalui pencincangan tidak begitu tinggi.
    • Strategi untuk menyelesaikan konflik kedudukan elemen tatasusunan semasa set juga mempengaruhi kaedah dapatkan.

    • 5. kaedah get
    • Kaedah get terutamanya mendapat nilai yang disimpan dalam ThreadLocal semasa daripada ThreadLocalMap Kod sumber adalah seperti berikut:

    • Kemudian mari kita. lihat kaedah getEntry ThreadLocalMap, kod sumber adalah seperti berikut:

    get Komen dalam kod sumber logik telah ditulis dengan sangat jelas, jadi kami tidak akan mengulanginya lagi .

    6. Pengembangan kapasiti

    Apabila bilangan ThreadLocals dalam ThreadLocalMap melebihi ambang, ThreadLocalMap akan mula berkembang >Anotasi kod sumber juga agak jelas Kami memberi perhatian kepada dua perkara:

    Selepas pengembangan, saiz tatasusunan adalah dua kali ganda daripada tatasusunan asal
    public T get() {
        // 因为 threadLocal 属于线程的属性,所以需要先把当前线程拿出来
        Thread t = Thread.currentThread();
        // 从线程中拿到 ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            // 从 map 中拿到 entry,由于 ThreadLocalMap 在 set 时的 hash 冲突的策略不同,导致拿的时候逻辑也不太一样
            ThreadLocalMap.Entry e = map.getEntry(this);
            // 如果不为空,读取当前 ThreadLocal 中保存的值
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        // 否则给当前线程的 ThreadLocal 初始化,并返回初始值 null
        return setInitialValue();
    }
    Salin selepas log masuk
    Apabila pengembangan Tiada isu keselamatan utas sama sekali, kerana ThreadLocalMap ialah atribut bagi utas A hanya boleh beroperasi pada ThreadLocalMap pada masa yang sama Kerana pelaksanaan logik perniagaan oleh utas yang sama mestilah bersiri pengendalian ThreadLocalMap juga mestilah bersiri.

    // 得到当前 thradLocal 对应的值,值的类型是由 thradLocal 的泛型决定的
    // 由于 thradLocalMap set 时解决数组索引位置冲突的逻辑,导致 thradLocalMap get 时的逻辑也是对应的
    // 首先尝试根据 hashcode 取模数组大小-1 = 索引位置 i 寻找,找不到的话,自旋把 i+1,直到找到索引位置不为空为止
    private Entry getEntry(ThreadLocal<?> key) {
        // 计算索引位置:ThreadLocal 的 hashCode 取模数组大小-1
        int i = key.threadLocalHashCode & (table.length - 1);
        Entry e = table[i];
        // e 不为空,并且 e 的 ThreadLocal 的内存地址和 key 相同,直接返回,否则就是没有找到,继续通过 getEntryAfterMiss 方法找
        if (e != null && e.get() == key)
            return e;
        else
        // 这个取数据的逻辑,是因为 set 时数组索引位置冲突造成的  
            return getEntryAfterMiss(key, i, e);
    }
    Salin selepas log masuk

    Atas ialah kandungan terperinci Penjelasan terperinci dan analisis kod sumber ThreadLocal dalam pengaturcaraan Java. 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

    AI Hentai Generator

    AI Hentai Generator

    Menjana ai hentai secara percuma.

    Artikel Panas

    R.E.P.O. Kristal tenaga dijelaskan dan apa yang mereka lakukan (kristal kuning)
    4 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O. Tetapan grafik terbaik
    4 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O. Cara Memperbaiki Audio Jika anda tidak dapat mendengar sesiapa
    4 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
    WWE 2K25: Cara Membuka Segala -galanya Di Myrise
    1 bulan yang lalu By 尊渡假赌尊渡假赌尊渡假赌

    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)

    Nombor Sempurna di Jawa Nombor Sempurna di Jawa Aug 30, 2024 pm 04:28 PM

    Panduan Nombor Sempurna di Jawa. Di sini kita membincangkan Definisi, Bagaimana untuk menyemak nombor Perfect dalam Java?, contoh dengan pelaksanaan kod.

    Penjana Nombor Rawak di Jawa Penjana Nombor Rawak di Jawa Aug 30, 2024 pm 04:27 PM

    Panduan untuk Penjana Nombor Rawak di Jawa. Di sini kita membincangkan Fungsi dalam Java dengan contoh dan dua Penjana berbeza dengan contoh lain.

    Weka di Jawa Weka di Jawa Aug 30, 2024 pm 04:28 PM

    Panduan untuk Weka di Jawa. Di sini kita membincangkan Pengenalan, cara menggunakan weka java, jenis platform, dan kelebihan dengan contoh.

    Nombor Smith di Jawa Nombor Smith di Jawa Aug 30, 2024 pm 04:28 PM

    Panduan untuk Nombor Smith di Jawa. Di sini kita membincangkan Definisi, Bagaimana untuk menyemak nombor smith di Jawa? contoh dengan pelaksanaan kod.

    Soalan Temuduga Java Spring Soalan Temuduga Java Spring Aug 30, 2024 pm 04:29 PM

    Dalam artikel ini, kami telah menyimpan Soalan Temuduga Spring Java yang paling banyak ditanya dengan jawapan terperinci mereka. Supaya anda boleh memecahkan temuduga.

    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

    TimeStamp to Date in Java TimeStamp to Date in Java Aug 30, 2024 pm 04:28 PM

    Panduan untuk TimeStamp to Date di Java. Di sini kita juga membincangkan pengenalan dan cara menukar cap waktu kepada tarikh dalam java bersama-sama dengan contoh.

    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

    See all articles