最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

重新認(rèn)識(shí)Java中的ThreadLocal

 更新時(shí)間:2021年05月31日 08:36:37   作者:Nicksxs''''s  
ThreadLocal是JDK包提供的,它提供線程本地變量,如果創(chuàng)建一個(gè)ThreadLocal變量,那么訪問(wèn)這個(gè)變量的每個(gè)線程都會(huì)有這個(gè)變量的一個(gè)副本,在實(shí)際多線程操作的時(shí)候,操作的是自己本地內(nèi)存中的變量,從而規(guī)避了線程安全問(wèn)題

說(shuō)來(lái)也慚愧,這個(gè) ThreadLocal 其實(shí)一直都是一知半解,而且看了一下之后還發(fā)現(xiàn)記錯(cuò)了,所以還是記錄下
原先記憶里的都是反過(guò)來(lái),一個(gè) ThreadLocal 是里面按照 thread 作為 key,存儲(chǔ)線程內(nèi)容的,真的是半解都米有,完全是錯(cuò)的,這樣就得用 concurrentHashMap 這種去存儲(chǔ)并且要鎖定線程了,然后內(nèi)容也只能存一個(gè)了,想想簡(jiǎn)直智障

究竟是啥結(jié)構(gòu)

比如我們?cè)诖a中 new 一個(gè) ThreadLocal,

public static void main(String[] args) {
        ThreadLocal<Man> tl = new ThreadLocal<>();

        new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(tl.get());
        }).start();
        new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            tl.set(new Man());
        }).start();
    }

    static class Man {
        String name = "nick";
    }

這里構(gòu)造了兩個(gè)線程,一個(gè)先往里設(shè)值,一個(gè)后從里取,運(yùn)行看下結(jié)果,

知道這個(gè)用法的話(huà)肯定知道是取不到值的,只是具體的原理原來(lái)搞錯(cuò)了,我們來(lái)看下設(shè)值 set 方法

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

寫(xiě)博客這會(huì)我才明白我原來(lái)咋會(huì)錯(cuò)得這么離譜,看到第一行代碼 t 就是當(dāng)前線程,然后第二行就是用這個(gè)線程去getMap,然后我是把這個(gè)當(dāng)成從 map 里取值了,其實(shí)這里是

ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}

獲取 t 的 threadLocals 成員變量,那這個(gè) threadLocals 又是啥呢

它其實(shí)是線程 Thread 中的一個(gè)類(lèi)型是java.lang.ThreadLocal.ThreadLocalMap的成員變量
這是 ThreadLocal 的一個(gè)靜態(tài)成員變量

static class ThreadLocalMap {

        /**
         * The entries in this hash map extend WeakReference, using
         * its main ref field as the key (which is always a
         * ThreadLocal object).  Note that null keys (i.e. entry.get()
         * == null) mean that the key is no longer referenced, so the
         * entry can be expunged from table.  Such entries are referred to
         * as "stale entries" in the code that follows.
         */
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }
    }

全部代碼有點(diǎn)長(zhǎng),只截取了一小部分,然后我們?cè)倩仡^來(lái)分析前面說(shuō)的 set 過(guò)程,再 copy 下代碼

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

獲取到 map 以后呢,如果 map 不為空,就往 map 里 set,這里注意 key 是啥,其實(shí)是當(dāng)前這個(gè) ThreadLocal,這里就比較明白了究竟是啥結(jié)構(gòu),每個(gè)線程都會(huì)維護(hù)自身的 ThreadLocalMap,它是線程的一個(gè)成員變量,當(dāng)創(chuàng)建 ThreadLocal 的時(shí)候,進(jìn)行設(shè)值的時(shí)候其實(shí)是往這個(gè) map 里以 ThreadLocal 作為 key,往里設(shè) value。

內(nèi)存泄漏是什么鬼

這里又要看下前面的 ThreadLocalMap 結(jié)構(gòu)了,類(lèi)似 HashMap,它有個(gè) Entry 結(jié)構(gòu),在設(shè)置的時(shí)候會(huì)先包裝成一個(gè) Entry

private void set(ThreadLocal<?> key, Object value) {

        // We don't use a fast path as with get() because it is at
        // least as common to use set() to create new entries as
        // it is to replace existing ones, in which case, a fast
        // path would fail more often than not.

        Entry[] tab = table;
        int len = tab.length;
        int i = key.threadLocalHashCode & (len-1);

        for (Entry e = tab[i];
             e != null;
             e = tab[i = nextIndex(i, len)]) {
            ThreadLocal<?> k = e.get();

            if (k == key) {
                e.value = value;
                return;
            }

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

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

這里其實(shí)比較重要的就是前面的 Entry 的構(gòu)造方法,Entry 是個(gè) WeakReference 的子類(lèi),然后在構(gòu)造方法里可以看到 key 會(huì)被包裝成一個(gè)弱引用,這里為什么使用弱引用,其實(shí)是方便這個(gè) key 被回收,如果前面的 ThreadLocal tl實(shí)例被設(shè)置成 null 了,如果這里是直接的強(qiáng)引用的話(huà),就只能等到線程整個(gè)回收了,但是其實(shí)是弱引用也會(huì)有問(wèn)題,主要是因?yàn)檫@個(gè) value,如果在 ThreadLocal tl 被設(shè)置成 null 了,那么其實(shí)這個(gè) value 就會(huì)沒(méi)法被訪問(wèn)到,所以最好的操作還是在使用完了就 remove 掉

以上就是詳解Java中的ThreadLocal的詳細(xì)內(nèi)容,更多關(guān)于Java ThreadLocal的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java基礎(chǔ)之toString的序列化 匿名對(duì)象 復(fù)雜度精解

    Java基礎(chǔ)之toString的序列化 匿名對(duì)象 復(fù)雜度精解

    序列化即為把內(nèi)存中的對(duì)象轉(zhuǎn)換為字節(jié)寫(xiě)入文件或通過(guò)網(wǎng)絡(luò)傳輸?shù)竭h(yuǎn)端服務(wù)器,本章節(jié)將帶你了解Java toString的序列化 匿名對(duì)象 復(fù)雜度,需要的朋友可以參考下
    2021-09-09
  • Java開(kāi)發(fā)中synchronized的定義及用法詳解

    Java開(kāi)發(fā)中synchronized的定義及用法詳解

    這篇文章主要介紹了Java開(kāi)發(fā)中synchronized的定義及用法詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Hibernate 與 Mybatis 的共存問(wèn)題,打破你的認(rèn)知!(兩個(gè)ORM框架)

    Hibernate 與 Mybatis 的共存問(wèn)題,打破你的認(rèn)知!(兩個(gè)ORM框架)

    這篇文章主要介紹了Hibernate 與 Mybatis 如何共存?本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-08-08
  • Java8中Stream流求最大值最小值的實(shí)現(xiàn)示例

    Java8中Stream流求最大值最小值的實(shí)現(xiàn)示例

    本文主要介紹了Java8中Stream流求最大值最小值的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • SpringBoot數(shù)據(jù)庫(kù)查詢(xún)超時(shí)配置詳解

    SpringBoot數(shù)據(jù)庫(kù)查詢(xún)超時(shí)配置詳解

    這篇文章主要介紹了SpringBoot數(shù)據(jù)庫(kù)查詢(xún)超時(shí)配置,超時(shí)配置可以避免長(zhǎng)時(shí)間占用數(shù)據(jù)庫(kù)連接,提高系統(tǒng)的響應(yīng)速度和吞吐量,還可以快速的反饋可以提升用戶(hù)體驗(yàn),避免用戶(hù)因長(zhǎng)時(shí)間等待而感到挫敗,文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下
    2024-11-11
  • 關(guān)于JSqlparser使用攻略(高效的SQL解析工具)

    關(guān)于JSqlparser使用攻略(高效的SQL解析工具)

    這篇文章主要介紹了關(guān)于JSqlparser使用攻略(高效的SQL解析工具),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • 學(xué)習(xí)Java設(shè)計(jì)模式之觀察者模式

    學(xué)習(xí)Java設(shè)計(jì)模式之觀察者模式

    這篇文章主要為大家介紹了Java設(shè)計(jì)模式中的觀察者模式,對(duì)Java設(shè)計(jì)模式感興趣的小伙伴們可以參考一下
    2016-01-01
  • postman中參數(shù)和x-www-form-urlencoded傳值的區(qū)別及說(shuō)明

    postman中參數(shù)和x-www-form-urlencoded傳值的區(qū)別及說(shuō)明

    在Postman中,參數(shù)傳遞有多種方式,其中params和x-www-form-urlencoded最為常用,Params主要用于URL中傳遞查詢(xún)參數(shù),適合GET請(qǐng)求和非敏感數(shù)據(jù),其特點(diǎn)是將參數(shù)作為查詢(xún)字符串附加在URL末尾,適用于過(guò)濾和排序等操作
    2024-09-09
  • Java開(kāi)發(fā)SSM框架微信退款的實(shí)現(xiàn)

    Java開(kāi)發(fā)SSM框架微信退款的實(shí)現(xiàn)

    這篇文章是Java微信退款的教程,退款之前用戶(hù)需要先進(jìn)行支付,支付之后才可以使用退款,非常具有實(shí)用價(jià)值,感興趣的小伙伴們可以參考一下
    2018-10-10
  • Java任務(wù)定時(shí)執(zhí)行器案例的實(shí)現(xiàn)

    Java任務(wù)定時(shí)執(zhí)行器案例的實(shí)現(xiàn)

    定時(shí)器會(huì)執(zhí)行指定的任務(wù),本文主要介紹了Java任務(wù)定時(shí)執(zhí)行器案例的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06

最新評(píng)論

墨脱县| 怀宁县| 城口县| 车险| 广东省| 桦南县| 洛川县| 黔西| 东丽区| 宁晋县| 教育| 兴义市| 麻城市| 望江县| 竹北市| 历史| 龙山县| 阿鲁科尔沁旗| 平和县| 明光市| 江孜县| 工布江达县| 贺兰县| 钟山县| 丰镇市| 峡江县| 固安县| 山东省| 洛川县| 威宁| 育儿| 米脂县| 汉川市| 海丰县| 平远县| 井研县| 云梦县| 濮阳市| 都江堰市| 无极县| 秀山|