欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

告訴你為什么?ThreadLocal?可以做到線程隔離

 更新時(shí)間:2022年07月26日 09:05:19   作者:劉水鏡  
對(duì)于 ThreadLocal 我們都不陌生,它的作用如同它的名字用于存放線程本地變量,這篇文章主要介紹了為什么?ThreadLocal?可以做到線程隔離,需要的朋友可以參考下

對(duì)于 ThreadLocal 我們都不陌生,它的作用如同它的名字——用于存放「線程本地」變量。

先通過(guò)一個(gè)小例子感受一下:

private static final ThreadLocal<String> threadLocal = new ThreadLocal<>();
public static void main(String[] args) throws Throwable {
    Thread threadOne = new Thread(()->{
        threadLocal.set("ThreadOne:" + Thread.currentThread().getName());
        log.info("線程 One 本地變量值為:{}", threadLocal.get());
        threadLocal.remove();
        log.info("線程 One remove 后本地變量值為:{}", threadLocal.get());
    });
    Thread threadTwo = new Thread(()->{
        threadLocal.set("ThreadTwo:" + Thread.currentThread().getName());
        log.info("線程 Two 本地變量值為:{}", threadLocal.get());
    });
    threadOne.start();
    threadTwo.start();
}

運(yùn)行結(jié)果:

線程 One 本地變量值為:ThreadOne:Thread-0
線程 One remove 后本地變量值為:null
線程 Two 本地變量值為:ThreadTwo:Thread-1

OK,從效果上看,ThreadLocal 確實(shí)是線程隔離的,那么,它是如何做到線程隔離的呢?下面我們扒一扒源碼,看看它是如何做到的:

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

set() 方法的邏輯如下:

  • 獲取當(dāng)前線程
  • 根據(jù)當(dāng)前線程獲取一個(gè) ThreadLocalMap 對(duì)象
  • 如果 map 不為 null 則保存
  • 如果 map 為 null 則創(chuàng)建一個(gè) map

getMap() 和 createMap() 方法都干了啥呢?我們點(diǎn)進(jìn)去看:

ThreadLocalMap getMap(Thread t) {
   return t.threadLocals;
}
void createMap(Thread t, T firstValue) {
   t.threadLocals = new ThreadLocalMap(this, firstValue);
}

進(jìn)入到兩個(gè)方法內(nèi)部后發(fā)現(xiàn),不管執(zhí)行哪個(gè)分支,最終是把值保存到了當(dāng)前線程的 threadLocals 屬性中。

查看 Thread 類的源碼,你會(huì)發(fā)現(xiàn)類中定義了一個(gè) threadLocals 屬性,且初始值為 null,其類型為T(mén)hreadLocal.ThreadLocalMap。

public class Thread implements Runnable {
// ...
   ThreadLocal.ThreadLocalMap threadLocals = null;
// ...
}

到此,我們發(fā)現(xiàn)了,原來(lái) ThreadLocal 就是把我們要傳遞的對(duì)象放到了當(dāng)前線程的 threadLocals 屬性中。也就是說(shuō)每個(gè)線程在用 ThreadLocal 保存對(duì)象時(shí),其實(shí)就是將對(duì)象放到了當(dāng)前線程實(shí)例對(duì)象的 threadLocals 屬性里面。這樣一來(lái)線程之間自然就是互相獨(dú)立的啦。

再看看 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();
}

private T setInitialValue() {
   T value = initialValue();
   Thread t = Thread.currentThread();
   ThreadLocalMap map = getMap(t);
   if (map != null)
       map.set(this, value);
   else
       createMap(t, value);
   return value;
}

ThreadLocal 的 get() 方法其實(shí)和 set() 方法邏輯很相似,先從當(dāng)前線程的 threadLocals 屬性中取,如果該屬性為 null,那么就初始化。

當(dāng)線程結(jié)束時(shí),會(huì)調(diào)用當(dāng)前線程實(shí)例的 exit() 方法,將 threadLocals 設(shè)置為 null,以便垃圾回收器將其回收掉。

// THread 類中的方法
private void exit() {
   // ...
   threadLocals = null;
   // ...
}

最后,有一點(diǎn)需要格外注意:用完 ThreadLocal 一定要記得手動(dòng)調(diào)用 remove() 方法,否則可能會(huì)產(chǎn)生臟數(shù)據(jù)甚至產(chǎn)生內(nèi)存泄漏。

為啥呢?上面不是說(shuō)線程結(jié)束時(shí),會(huì)將 threadLocals 置為 null 嗎?

是的,線程結(jié)束時(shí),確實(shí)會(huì)做清理工作。

但,如果線程一直不結(jié)束呢?如果線程會(huì)被復(fù)用呢?比如使用了線程池。

所以,使用 ThreadLocal 一定要手動(dòng) remove()。?

補(bǔ)充:下面看下ThreadLocal 是什么?有哪些使用場(chǎng)景?

ThreadLocal是一個(gè)本地線程副本變量工具類,主要用于將私有線程和該線程存放的副本對(duì)象做一個(gè)映射,各個(gè)線程之間的變量互不干擾。

說(shuō)人話就是,ThreadLocal在每個(gè)線程都創(chuàng)建副本,每個(gè)線程可以訪問(wèn)自己的副本,線程之間相互不影響。

使用場(chǎng)景:

多線程環(huán)境中為每一個(gè)jdbc分配一個(gè)Connection連接,使用ThreadLocal去保存連接,這樣就保證了每個(gè)線程在自己的連接上操作數(shù)據(jù)庫(kù),不會(huì)出現(xiàn)A線程關(guān)閉B的Connnection操作

Web中的session管理時(shí),可以使用ThreadLocal記錄每個(gè)線程的Session,這樣保證每個(gè)線程都可以獲取自己的session

解決線程安全問(wèn)題,對(duì)于需要進(jìn)行線程隔離的變量,可以使用ThreadLocal存儲(chǔ),確保線程隔離

總結(jié):

ThreadLocal可以簡(jiǎn)單看作一個(gè)map,每個(gè)線程保存一個(gè)map,這個(gè)map只能存儲(chǔ)一組數(shù)據(jù),key為線程id, value就是要存的值

一個(gè)ThreadLocal只能存儲(chǔ)一個(gè)變量,如果要存多個(gè)就創(chuàng)建多個(gè)ThreadLocal對(duì)象。

到此這篇關(guān)于為什么 ThreadLocal 可以做到線程隔離?的文章就介紹到這了,更多相關(guān)ThreadLocal 線程隔離內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 創(chuàng)建SpringBoot工程并集成Mybatis的方法

    創(chuàng)建SpringBoot工程并集成Mybatis的方法

    這篇文章主要介紹了創(chuàng)建SpringBoot工程并集成Mybatis,需要的朋友可以參考下
    2018-06-06
  • Spring的事務(wù)控制實(shí)現(xiàn)方法

    Spring的事務(wù)控制實(shí)現(xiàn)方法

    這篇文章主要為大家詳細(xì)介紹了Spring的事務(wù)控制實(shí)現(xiàn)方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • Java利用位運(yùn)算實(shí)現(xiàn)乘法運(yùn)算詳解

    Java利用位運(yùn)算實(shí)現(xiàn)乘法運(yùn)算詳解

    這篇文章主要為大家詳細(xì)介紹了Java如何用位運(yùn)算實(shí)現(xiàn)乘法運(yùn)算,在實(shí)現(xiàn)乘法時(shí)要用位運(yùn)算實(shí)現(xiàn),并且不能出現(xiàn)加減乘除任何符號(hào),感興趣的可以了解一下
    2023-04-04
  • Java實(shí)現(xiàn)FTP上傳與下載功能

    Java實(shí)現(xiàn)FTP上傳與下載功能

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)FTP上傳與下載功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • 史上最全的IDEA快捷鍵總結(jié)

    史上最全的IDEA快捷鍵總結(jié)

    這篇文章主要介紹了史上最全的IDEA快捷鍵總結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • 如何實(shí)現(xiàn)java8 list按照元素的某個(gè)字段去重

    如何實(shí)現(xiàn)java8 list按照元素的某個(gè)字段去重

    這篇文章主要介紹了如何實(shí)現(xiàn)java8 list按照元素的某個(gè)字段去重,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,,需要的朋友可以參考下
    2019-06-06
  • maven搭建spring項(xiàng)目(圖文教程)

    maven搭建spring項(xiàng)目(圖文教程)

    下面小編就為大家?guī)?lái)一篇maven搭建spring項(xiàng)目(圖文教程)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-06-06
  • springcloud整合seata的實(shí)現(xiàn)代碼

    springcloud整合seata的實(shí)現(xiàn)代碼

    這篇文章主要介紹了springcloud整合seata的實(shí)現(xiàn)方法,整合步驟通過(guò)引入spring-cloud-starter-alibaba-seata?jar包,文中結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-05-05
  • JVM調(diào)試命令與調(diào)試工具詳解

    JVM調(diào)試命令與調(diào)試工具詳解

    JVM statistics Monitoring,用于監(jiān)視虛擬機(jī)運(yùn)行時(shí)狀態(tài)信息的命令,它可以顯示出虛擬機(jī)進(jìn)程中的類裝載、內(nèi)存、垃圾收集、JIT編譯等運(yùn)行數(shù)據(jù),這篇文章主要介紹了JVM調(diào)試命令與調(diào)試工具,需要的朋友可以參考下
    2023-10-10
  • 淺談java Collection中的排序問(wèn)題

    淺談java Collection中的排序問(wèn)題

    下面小編就為大家?guī)?lái)一篇淺談java Collection中的排序問(wèn)題。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-12-12

最新評(píng)論