日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

InheritableThreadLocal 是如何實現的父子線程局部變量的傳遞

來源: 責編: 時間:2024-07-09 18:20:03 259觀看
導讀今天聊一聊并發編程中經常遇到也是面試時容易被為難的一個題目,線程間局部變量的傳遞問題。相信對并發編程有一定了解的同學已經想到了大名鼎鼎的 ThreadLocal 了,是的,線程內部就是通過 inheritableThreadLocals 實現了

今天聊一聊并發編程中經常遇到也是面試時容易被為難的一個題目,線程間局部變量的傳遞問題。zTh28資訊網——每日最新資訊28at.com

相信對并發編程有一定了解的同學已經想到了大名鼎鼎的 ThreadLocal 了,是的,線程內部就是通過 inheritableThreadLocals 實現了父子線程間局部變量的傳遞。zTh28資訊網——每日最新資訊28at.com

JDK 8zTh28資訊網——每日最新資訊28at.com

zTh28資訊網——每日最新資訊28at.com

zTh28資訊網——每日最新資訊28at.com

一、父子線程間局部變量參數傳遞的方式 ThreadLocal

首先我們寫看一段代碼:zTh28資訊網——每日最新資訊28at.com

public class ThreadLocalTest implements Runnable{    private static final InheritableThreadLocal<String> MAIN_THREAD_LOCAL = new InheritableThreadLocal<>();    @SneakyThrows    @Override    public void run() {        System.out.println("threadlocal 默認值:"+ThreadLocalTest.MAIN_THREAD_LOCAL.get());        MAIN_THREAD_LOCAL.set("child thread value :"+Thread.currentThread().getName());        System.out.println("threadlocal 設置子線程值之后:"+ThreadLocalTest.MAIN_THREAD_LOCAL.get());    }    public String get(){        return MAIN_THREAD_LOCAL.get();    }    public void clean(){        MAIN_THREAD_LOCAL.remove();    }    public static void main(String[] args) {        ThreadLocalTest threadLocalTest = new ThreadLocalTest();        MAIN_THREAD_LOCAL.set("父線程的值 set 111");        System.out.println("啟動:"+threadLocalTest.get());        for (int i = 0; i < 3; i++) {            new Thread(threadLocalTest).start();//            ThreadUtil.execAsync(threadLocalTest);        }        System.out.println("結束:"+threadLocalTest.get());    }}

在上面的這段代碼中,我們就做了三個事情:zTh28資訊網——每日最新資訊28at.com

  • 設置父線程中定義ThreadLocal的值。
  • 在子線程中打印父線程中ThreadLocal的值。
  • 啟動多個子線程

大家可以先猜一下這段代碼的運行結果。zTh28資訊網——每日最新資訊28at.com

二、子線程可以繼承父線程局部變量的值嗎

首先我們先說下答案,是可以繼承的。上面代碼的執行結果如下:zTh28資訊網——每日最新資訊28at.com

啟動:父線程的值 set 111結束:父線程的值 set 111threadlocal 默認值:父線程的值 set 111threadlocal 設置子線程值之后:child thread value :Thread-1threadlocal 默認值:父線程的值 set 111threadlocal 默認值:父線程的值 set 111threadlocal 設置子線程值之后:child thread value :Thread-2threadlocal 設置子線程值之后:child thread value :Thread-0

在上面的代碼中,我們的子線程優先打印了父線程中ThreadLocal的值,然后重新設置該值,再次讀取。得出結論就是子線程可以通過ThreadLocal繼承父線程的值,并且子線程自己內容再次重新設置不影響父線程的值。zTh28資訊網——每日最新資訊28at.com

三、父子線程局部變量傳值的原理

難道一句簡單的ThreadLocal就可以讓我們對這個問題停止探索嗎?那么線程內部是如何通過ThreadLocal進行傳值的呢?zTh28資訊網——每日最新資訊28at.com

1.new thread

在上面代碼中,啟動子線程的方式是new Thread(threadLocalTest).start();,所以秘密一定就在這一行代碼里面。源碼之下無秘密,我們一起來看下。zTh28資訊網——每日最新資訊28at.com

首先進入new Thread()的內部:zTh28資訊網——每日最新資訊28at.com

    public Thread(Runnable target) {        init(null, target, "Thread-" + nextThreadNum(), 0);    }    private void init(ThreadGroup g, Runnable target, String name,                      long stackSize) {        init(g, target, name, stackSize, null, true);    }

通過上面兩個方法調用,最終進入到下面這個方法中:zTh28資訊網——每日最新資訊28at.com

 private void init(ThreadGroup g, Runnable target, String name,                      long stackSize, AccessControlContext acc,                      boolean inheritThreadLocals) {}

init方法有個參數inheritThreadLocals,boolean類型的,如果為true,且可繼承的線程局部變量不為空就繼承。zTh28資訊網——每日最新資訊28at.com

zTh28資訊網——每日最新資訊28at.com

現在我們只需要順著inheritThreadLocals這個參數去找就可以了,在Thread的418行,有這樣一行代碼。(代碼行數可能因版本而位置不同)zTh28資訊網——每日最新資訊28at.com

zTh28資訊網——每日最新資訊28at.com

可以看到是直接對當前線程的inheritableThreadLocals直接進行的賦值操作,而值是通過ThreadLocal.createInheritedMap獲取的,下面我們看下這個createInheritedMap方法做了哪些操作?zTh28資訊網——每日最新資訊28at.com

zTh28資訊網——每日最新資訊28at.com

zTh28資訊網——每日最新資訊28at.com

createInheritedMap方法是ThredLocal內部的方法,接收傳遞父線程的ThreadLocalMap為參數,該方法只做了一個事情,就是new了一個新的ThreadLocalMap。zTh28資訊網——每日最新資訊28at.com

跟進到new ThreadLocalMap(parentMap)方法內部,其實是把傳進的值,一個個的遍歷進行賦值到當前線程中。zTh28資訊網——每日最新資訊28at.com

zTh28資訊網——每日最新資訊28at.com

對于圖中標記的第二個地方,childValue調用的是InheritableThreadLocal#childValue,該方法內也只做了一件事,就是返回傳進來的值。zTh28資訊網——每日最新資訊28at.com

zTh28資訊網——每日最新資訊28at.com

(1) 小結zTh28資訊網——每日最新資訊28at.com

父子線程之所以能傳參,是因為我們使用了InheritableThreadLocal,這樣在new Thread()時,就會進入到給子線程賦值父線程inheritableThreadLocals的邏輯中去。zTh28資訊網——每日最新資訊28at.com

(2) 擴展zTh28資訊網——每日最新資訊28at.com

有的同學會說了,我用 ThreadLocal.withInitial創建的,怎么走到線程的if (inheritThreadLocals && parent.inheritableThreadLocals != null)判斷時,沒有進去呢,上面不是說是在這判斷然后對子線程進行賦值的嗎?zTh28資訊網——每日最新資訊28at.com

在這簡單說一下哈,大家在寫代碼時,或者再用第三方框架時,源碼中的注釋一定要看仔細,很多細節都在注釋中標注清楚了。zTh28資訊網——每日最新資訊28at.com

    public static ThreadLocal<String> MAIN_THREAD_LOCAL = ThreadLocal.withInitial(() -> "父線程的值 withInitial 111");

在上面的代碼中,我們進行了ThreadLocal的初始化賦值,然后看下withInitial方法。zTh28資訊網——每日最新資訊28at.com

zTh28資訊網——每日最新資訊28at.com

所以是當調用get方法時,才會觸發賦值的操作,那么我們看下get方法。zTh28資訊網——每日最新資訊28at.com

zTh28資訊網——每日最新資訊28at.com

如果當前線程的局部變量沒有值,返回初始化方法初始的值。zTh28資訊網——每日最新資訊28at.com

所以對于我們來說就是SuppliedThreadLocal#initialValue返回的值。zTh28資訊網——每日最新資訊28at.com

zTh28資訊網——每日最新資訊28at.com

2.線程池

剛才我們是通過new Thread()啟動的子線程,可是工作中基本都是通過線程池的方式執行任務的啊,那還生效嗎?zTh28資訊網——每日最新資訊28at.com

答案是生效。zTh28資訊網——每日最新資訊28at.com

我們使用hutool工具中的ThreadUtil.execAsync(threadLocalTest);進行測試。zTh28資訊網——每日最新資訊28at.com

直接說結論,感興趣的同學可以自行修改一下代碼中的子線程啟動方式。zTh28資訊網——每日最新資訊28at.com

先畫個流程圖,大家可以跟著代碼走一下。zTh28資訊網——每日最新資訊28at.com

zTh28資訊網——每日最新資訊28at.com

當使用線程池時,底層原理還是線程池中放入任務的邏輯,當放入線程池之后,會在AbstractExecutorService#submit()方法中執行execute方法,最終執行在ThreadPoolExecutor#execute(),在這里,就是把任務丟入線程池工作的邏輯,其中有個方法addWorker,該方法中有一行new Worker(),而在該Worker方法的內部,其實就是new Thread(),到了這,就與上面所說的一樣了,到了判斷inheritableThreadLocals的時候了。zTh28資訊網——每日最新資訊28at.com

zTh28資訊網——每日最新資訊28at.com

zTh28資訊網——每日最新資訊28at.com

zTh28資訊網——每日最新資訊28at.com

zTh28資訊網——每日最新資訊28at.com

四、如何解決內存泄漏

使用ThreadLocal的應用場景有很多,父子線程傳參數的場景也有不少,但是有一個很關鍵的點內存溢出是需要重視的。解決ThreadLocal內存溢出的方式也很簡單,就是在使用完成之后調用一下remove。zTh28資訊網——每日最新資訊28at.com

對于上面的代碼示例,就是調用我們的clean方法。zTh28資訊網——每日最新資訊28at.com

zTh28資訊網——每日最新資訊28at.com

public void clean(){ MAIN_THREAD_LOCAL.remove();}

zTh28資訊網——每日最新資訊28at.com

remove的代碼如下,取值不為null時,執行刪除邏輯。zTh28資訊網——每日最新資訊28at.com

zTh28資訊網——每日最新資訊28at.com

zTh28資訊網——每日最新資訊28at.com

zTh28資訊網——每日最新資訊28at.com

五、總結

我們通過一個示例,驗證了父子線程間可以通過ThreadLocal進行傳遞,測試了不同方式初始化ThreadLocal,并對比了new Thread()與線程池啟動的區別。zTh28資訊網——每日最新資訊28at.com

其實殊途同歸,線程池最后調用的還是Thread里面的方法。唯一需要注意的就是通過ThreadLocal.withInitial初始化是在get時賦值的,不過這個應該也不重要,了解一下就好,應該也沒有面試官會這么摳這個問題吧。zTh28資訊網——每日最新資訊28at.com

本文鏈接:http://m.www897cc.com/showinfo-26-99899-0.htmlInheritableThreadLocal 是如何實現的父子線程局部變量的傳遞

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 利用依賴結構矩陣管理架構債務

下一篇: 軟件架構中的九種耦合形式

標簽:
  • 熱門焦點
Top 日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不
久久久夜夜夜| 99www免费人成精品| 欧美日韩精品免费观看| 欧美精品乱人伦久久久久久 | 麻豆视频一区二区| 久久国产手机看片| 久久久综合免费视频| 免费美女久久99| 欧美久久视频| 国产精品毛片va一区二区三区 | 欧美伦理视频网站| 欧美日韩国产页| 国产精品对白刺激久久久| 国产精品一区二区在线观看网站| 国产女主播在线一区二区| 国产一区在线观看视频| 亚洲福利久久| 日韩亚洲一区二区| 亚洲欧美日韩综合| 久久综合999| 欧美日韩精品一区二区在线播放| 国产亚洲免费的视频看| 亚洲乱码国产乱码精品精98午夜| 香蕉免费一区二区三区在线观看| 女人天堂亚洲aⅴ在线观看| 国产精品第三页| 亚洲国产成人精品久久久国产成人一区 | 国产专区精品视频| 一区二区免费在线观看| 久久香蕉国产线看观看av| 欧美色区777第一页| 精品动漫3d一区二区三区| 亚洲精品乱码视频| 99天天综合性| 久久精品官网| 欧美久久精品午夜青青大伊人| 国产精品黄色在线观看| 在线观看av不卡| 亚洲午夜免费福利视频| 鲁大师成人一区二区三区 | 亚洲欧洲精品一区| 午夜久久tv| 欧美激情片在线观看| 欧美色偷偷大香| 一区二区在线看| 亚洲男人第一av网站| 牛牛精品成人免费视频| 国产精品一区二区三区乱码| 91久久精品网| 久久成人精品| 欧美午夜www高清视频| 精品福利电影| 亚洲综合视频网| 欧美黄色影院| 黄色欧美成人| 中文亚洲免费| 老司机精品导航| 国产精品亚洲产品| 99re这里只有精品6| 久久久在线视频| 国产酒店精品激情| 妖精视频成人观看www| 久久久精品国产99久久精品芒果| 欧美日韩一区二区视频在线| 在线观看精品视频| 欧美一区二区视频97| 欧美日韩综合不卡| 亚洲欧洲精品一区二区三区波多野1战4| 亚洲欧美综合一区| 欧美肉体xxxx裸体137大胆| 亚洲国产一区二区a毛片| 久久国产综合精品| 国产精品天天看| 一本色道精品久久一区二区三区| 欧美一区二区日韩一区二区| 欧美性猛片xxxx免费看久爱| 亚洲人成小说网站色在线 | 欧美少妇一区| 亚洲精品美女免费| 99在线精品视频| 模特精品在线| 在线精品一区二区| 久久免费视频在线观看| 国产视频欧美| 欧美一级大片在线免费观看| 欧美午夜宅男影院| 一本色道久久88综合日韩精品| 欧美成人黄色小视频| 一区免费观看视频| 久久久久久亚洲精品中文字幕| 国产女人水真多18毛片18精品视频| 亚洲午夜视频| 国产精品久久久久久久久免费| 99国产精品国产精品毛片| 欧美激情a∨在线视频播放| 亚洲高清久久网| 美女精品网站| 亚洲第一主播视频| 蜜臀久久99精品久久久久久9| 精品999久久久| 久久在线观看视频| 亚洲成人在线网| 美女啪啪无遮挡免费久久网站| 在线观看不卡| 嫩草影视亚洲| 91久久国产综合久久91精品网站| 嫩草国产精品入口| 亚洲人成在线影院| 欧美日韩国产123| 在线视频一区二区| 国产精品久久中文| 亚洲影音一区| 国产欧美一区二区三区在线老狼| 欧美一区二区在线观看| 国产视频亚洲精品| 久久久久欧美精品| 亚洲国产日韩欧美在线99| 欧美视频在线一区二区三区| 欧美一级免费视频| 1024亚洲| 国产精品第十页| 久久亚洲不卡| 中文av一区二区| 韩国亚洲精品| 欧美日韩亚洲国产一区| 午夜视频在线观看一区二区三区| 极品尤物av久久免费看| 欧美日韩一区高清| 久久久久久久网| 一区二区三区四区国产| 国色天香一区二区| 欧美日韩国产大片| 久久精品一区二区国产| 亚洲人成绝费网站色www| 国产精品少妇自拍| 欧美电影在线观看完整版| 亚洲综合好骚| 91久久精品国产91久久性色tv| 国产精品免费一区二区三区观看| 久久久久久久国产| 在线一区二区三区四区| 狠狠色伊人亚洲综合网站色| 欧美日韩日日骚| 久久夜色精品亚洲噜噜国产mv| 中国日韩欧美久久久久久久久| 黄色一区二区在线观看| 欧美午夜女人视频在线| 美女主播精品视频一二三四| 亚洲欧美日韩在线一区| 亚洲精品在线观| 红杏aⅴ成人免费视频| 欧美视频在线一区| 美日韩精品免费观看视频| 性欧美暴力猛交69hd| 日韩一级大片在线| 在线观看的日韩av| 国产精品综合久久久| 欧美日韩精品免费观看视频完整 | 亚洲午夜av在线| 亚洲高清在线| 国产亚洲毛片在线| 国产精品xxxxx| 欧美精品久久一区| 免费久久久一本精品久久区| 亚洲在线1234| 99在线观看免费视频精品观看| 在线不卡欧美| 国产日韩亚洲欧美精品| 国产精品国产三级欧美二区| 欧美伦理在线观看| 米奇777在线欧美播放| 欧美中文字幕在线视频| 亚洲在线成人| 一区二区三区成人| 日韩视频免费在线| 亚洲日本成人| 亚洲第一区中文99精品| 狠狠色丁香婷婷综合影院| 国产欧美精品一区| 欧美性猛交xxxx乱大交退制版| 欧美精品一区三区| 欧美福利视频在线观看| 蜜桃久久精品乱码一区二区| 久久久久在线| 久久久高清一区二区三区| 欧美亚洲在线| 午夜在线一区| 亚洲欧美日韩成人| 亚洲综合第一页| 亚洲影视综合| 亚洲欧美精品一区| 亚洲欧美日韩网| 欧美一区二区三区在| 亚欧美中日韩视频| 欧美在线短视频| 久久www免费人成看片高清| 欧美一区二区三区免费观看| 欧美一级播放| 久久精彩免费视频| 久久久91精品国产一区二区精品| 久久精品一区二区三区四区| 久久精品男女| 米奇777超碰欧美日韩亚洲| 欧美+亚洲+精品+三区|