国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

您有一份ThreadLocal完全解析手冊(cè)

劉東 / 2127人閱讀

摘要:返回索引位置的值。因?yàn)橐蕾?lài)于靜態(tài)成員變量的關(guān)系,所以它的肯定唯一獲取當(dāng)前線程。位置還沒(méi)有初始化第一次這個(gè),直接將放到的位置。在線程池模式下,生命周期伴隨著線程一直存在,可能出現(xiàn)內(nèi)存泄漏的情況,最好手動(dòng)調(diào)用方法。

本文原創(chuàng)地址,:jsbintask的博客(食用效果最佳),轉(zhuǎn)載請(qǐng)注明出處!

前言

ThreadLocal是jdk中一個(gè)非常重要的工具,它可以控制堆內(nèi)存中的對(duì)象只能被指定線程訪問(wèn),如果你經(jīng)常閱讀源碼,基本在各大框架都能發(fā)現(xiàn)它的蹤影。而它最經(jīng)典的應(yīng)用就是事務(wù)管理,同時(shí)它也是面試中的常客。

原理

我們知道,堆內(nèi)存是共享的,為什么ThreadLocal能夠控制指定線程訪問(wèn)呢? 如圖:

    調(diào)用ThreadLocal的get方法。

    獲取當(dāng)前線程t1.

    獲取t1的成員變量ThreadLocalMap

    根據(jù)ThreadLocal的hashcode計(jì)算出ThreadLocalMap中Entry[]數(shù)組的索引。

    返回索引位置的值。 這樣我們就很容易理解了,為什么只有當(dāng)前線程才能獲取到某些值,因?yàn)檫@是這些值都直接保存在當(dāng)前線程的成員變量ThreadLocalMap中,而ThreadLocal在這個(gè)過(guò)程中充當(dāng)?shù)慕巧珓t是提供它獨(dú)一無(wú)二的hashcode值,這樣我們就能計(jì)算出我們保存的值在ThreadLocalMap的位置。

源碼分析

我們從構(gòu)建一個(gè)ThreadLocal到調(diào)用它的set,get方法完整的分析一遍它的源碼。

構(gòu)造器

當(dāng)我們使用new ThreadLocal<>() new一個(gè)ThreadLocal對(duì)象時(shí),它初始化了一個(gè)成員變量threadLocalHashCode,這個(gè)成員變量代表當(dāng)前ThreadLocal的hashcode值,而它肯定是唯一的:

    ThreadLocal內(nèi)部有一個(gè)靜態(tài)hashCode生成器nextHashCode

    每次新new一個(gè)ThreadLocal對(duì)象,調(diào)用這個(gè)生成器同步方法獲取hashcode。 因?yàn)橐蕾?lài)于靜態(tài)成員變量nextHashCode的關(guān)系,所以它的hashcode肯定唯一!

set(T t)
public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}

    獲取當(dāng)前線程t。

    從t中獲取ThreadLocalMap map。

    如果map不為空,將當(dāng)前值value放入map。

    如果map為空,新建一個(gè)ThreadLocalMap放入線程t。 ThreadLocalMap是ThreadLocal中的內(nèi)部類(lèi),它的結(jié)構(gòu)如下:

public class ThreadLocalMap {
    
    static class Entry extends WeakReference<ThreadLocal<");{
        Object value;

        Entry(ThreadLocal<");super(k);
            value = v;
        }
    }

    private Entry[] table;
    
    private int size = 0;
    
    private static final int INITIAL_CAPACITY = 16;
    
    private int threshold; // Default to 0
}

類(lèi)似于ArrayList內(nèi)部的構(gòu)造,它內(nèi)部有一個(gè)Entry數(shù)組table,并且Entry繼承自弱引用(gc時(shí)保存的ThreadLocal會(huì)被標(biāo)記清理),所以每一個(gè)Entry中保存著兩個(gè)值,ThreadLocal,value,value既是我們要保存的值。 接著,我們回過(guò)頭詳細(xì)分析第三步,ThreadLocalMap的set方法:

private void set(ThreadLocal<"); {
            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);  // 1

            for (Entry e = tab[i];
                 e != null;         // 2
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal<");if (k == key) {   // 3
                    e.value = value;
                    return;
                }

                if (k == null) {   // 4
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }

            tab[i] = new Entry(key, value);  // 5
            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold)   // 6
                rehash();
        }

    根據(jù)ThreadLocal的hashCode計(jì)算出在entry中的索引i。

    取出i對(duì)應(yīng)的Entry值e。

    如果e的key等于當(dāng)前ThreadLocal,代表已經(jīng)有一個(gè)一樣的ThreadLocal在這個(gè)entry設(shè)值,直接替換這個(gè)entry上的value。

    e上面的ThreadLocal為null,代表垃圾收集器準(zhǔn)備回收這個(gè)Entry了,重新計(jì)算數(shù)組大小,重新hash。

    i位置還沒(méi)有初始化(第一次set這個(gè)ThreadLocal),直接將value放到i的位置。

    擴(kuò)容Entry數(shù)組。

get()
public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}

    獲取當(dāng)前線程。

    從當(dāng)前線程中獲取ThreadLocalMap

    從ThreadLocalMap中找出ThreadLocal對(duì)應(yīng)的Entry.

    如果Entry不為null,直接返回Entry中的value

    返回初始值。 其中,ThreadLocalMap的get(ThreadLocal tl)如下:

    它和我們一開(kāi)始的分析一樣,根據(jù)ThreadLocal的hashcode成員變量計(jì)算出索引位置i,得到Entry。這里同樣有特殊情況,如果得到的Entry的key和當(dāng)前ThreadLocal不相等,代表這個(gè)Entry將被垃圾收集處理,調(diào)用getEntryAfterMiss rehash,計(jì)算數(shù)組大小。

注意事項(xiàng)

從上面的代碼分析中,我們知道,ThreadLocalMap的生命周期和當(dāng)前線程同步,如果當(dāng)前線程被銷(xiāo)毀,則map中的所有引用均被銷(xiāo)毀。但如果當(dāng)前線程不被銷(xiāo)毀呢(線程池,tomcat處理請(qǐng)求等)?Entry中保存了ThreadLocal的弱引用以及value,gc時(shí)可能清理掉ThreadLocal,而這個(gè)value確再?zèng)]有訪問(wèn)之地,這個(gè)時(shí)候就會(huì)造成內(nèi)存泄漏! 所以我們需要手動(dòng)調(diào)用remove方法清理掉當(dāng)前線程ThreadLocalMap的引用!

總結(jié)

    ThreadLocal中真正保存的值還是在線程的ThreadLocalMap中,ThreadLocal只是使用它的hashcode值充當(dāng)中間計(jì)算變量。

    ThreadLocalMap內(nèi)部使用一個(gè)Entry數(shù)組保存數(shù)據(jù),它根據(jù)ThreadLocal計(jì)算出來(lái)的hashcode得到Entry的索引值,而ThreadLocal的hashcod在其內(nèi)部的靜態(tài)工具類(lèi)產(chǎn)生,所以不會(huì)出現(xiàn)沖突。

    在線程池模式下,ThreadLocal生命周期伴隨著線程一直存在,可能出現(xiàn)內(nèi)存泄漏的情況,最好手動(dòng)調(diào)用remove方法。

關(guān)注我,這里只有干貨!

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/7868.html

相關(guān)文章

  • ThreadLocal 線程安全機(jī)制與小地雷

    摘要:多線程類(lèi)庫(kù)對(duì)于共享數(shù)據(jù)的讀寫(xiě)控制主要采用鎖機(jī)制保證線程安全,本文所要探究的則采用了一種完全不同的策略。所以出現(xiàn)內(nèi)存泄露的前提必須是持有的線程一直存活,這在使用線程池時(shí)是很正常的,在這種情況下一直不會(huì)被,因?yàn)? Java 多線程類(lèi)庫(kù)對(duì)于共享數(shù)據(jù)的讀寫(xiě)控制主要采用鎖機(jī)制保證線程安全,本文所要探究的 ThreadLocal 則采用了一種完全不同的策略。ThreadLocal 不是用來(lái)解決共享數(shù)...

    xiao7cn 評(píng)論0 收藏0
  • Java 線程相關(guān)類(lèi)

    摘要:提供了線程安全的共享對(duì)象,在編寫(xiě)多線程代碼時(shí),可把不安全的整個(gè)變量封裝進(jìn),或者把該對(duì)象與線程相關(guān)的狀態(tài)使用保存并不能替代同步機(jī)制,兩者面向的問(wèn)題領(lǐng)域不同。 ThreadLocal類(lèi) 使用ThreadLocal類(lèi)可以簡(jiǎn)化多線程編程時(shí)的并發(fā)訪問(wèn),使用這個(gè)工具類(lèi)可以很簡(jiǎn)捷地隔離多線程程序的競(jìng)爭(zhēng)資源。Java5之后,為T(mén)hreadLocal類(lèi)增加了泛型支持,即ThreadLocal Threa...

    Sanchi 評(píng)論0 收藏0
  • Java多線程基礎(chǔ)-ThreadLocal

    摘要:并沒(méi)有提供語(yǔ)言級(jí)的線程局部變量,而是在類(lèi)庫(kù)里提供了線程局部變量的功能,也就是這次的主角類(lèi)。 Yuicon 轉(zhuǎn)載請(qǐng)注明原創(chuàng)出處,謝謝! 序 在多線程環(huán)境下,訪問(wèn)非線程安全的變量時(shí)必須進(jìn)行線程同步,例如使用synchronized方式訪問(wèn)HashMap實(shí)例。但是同步訪問(wèn)會(huì)降低并發(fā)性,影響系統(tǒng)性能。這時(shí)候就可以用空間換時(shí)間,如果我們給每個(gè)線程都分配一個(gè)獨(dú)立的變量,就可以用非同步的方式使用非...

    JasonZhang 評(píng)論0 收藏0
  • java學(xué)習(xí)(十) —— java中的多線程概述

    摘要:進(jìn)程一般由程序數(shù)據(jù)集進(jìn)程控制塊三部分組成。線程概述線程的出現(xiàn)是為了降低上下文切換的消耗,提高系統(tǒng)的并發(fā)性。線程突破了一個(gè)進(jìn)程只能干一件事的缺陷,使到進(jìn)程內(nèi)并發(fā)成為可能。進(jìn)程與線程的關(guān)系進(jìn)程是計(jì)算機(jī)中的程序關(guān)于某數(shù)據(jù)集合上的一次運(yùn)行活動(dòng)。 進(jìn)程概述 進(jìn)程:正在運(yùn)行的程序,是系統(tǒng)進(jìn)行資源分配和調(diào)用的獨(dú)立單位。 進(jìn)程就是一個(gè)程序在一個(gè)數(shù)據(jù)集上的一次動(dòng)態(tài)執(zhí)行過(guò)程。 進(jìn)程一般由程序、數(shù)據(jù)集、進(jìn)...

    Sanchi 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<