聊聊ThreadLocal

1. 自己的一些感受

在我自己的知識庫里面,一直是知道由ThreadLocal這么一個東西的荠列,也知道這是一個通過線程隔離資源解決并發(fā)的刽酱,但是卻對于使用場景和具體實現(xiàn)很模糊。

  • 它是如何跟線程掛鉤的邮偎?
  • 在同一個線程中管跺,有多個ThreadLocal又是如何存儲的?
  • 我們用它來解決什么問題呢禾进?

2. 先聊并發(fā)導致線程不安全的原因

  • 不能保證原子性
  • 不能保證有序性
  • 不能保證可見性
    更重要的一個前提是豁跑,需要有競態(tài)條件,多線程共享一個變量資源泻云,如果這個前提條件都沒有艇拍,就不存在所謂的并發(fā)安全性問題了。

3. ThreadLocal

  1. 從名字上來看宠纯,大致意思是”線程本地“變量卸夕;
  2. 本質(zhì)上,ThreadLocal確實是每個線程獨立擁有婆瓜,不共享的快集。
  3. ThreadLocal保證并發(fā)安全是因為線程資源的隔離,導致并不具備競態(tài)條件廉白,所以天然的不會存在線程安全性問題个初。

通過查詢源碼我們可以看一下ThreadLocal這個類的結構:


ThreadLocal Structure
  • 靜態(tài)內(nèi)部類: ThreadLocalMap. 用于實際存儲本地變量數(shù)據(jù)的


    ThreadLocalMap

    從這里面可以看出兩點:1. 弱引用存儲數(shù)據(jù)可能存在垃圾回收導致作為key的ThreadLocal對象回收,而value存在猴蹂。這個時候始終存在一個強引用的value對象不會被gc回收院溺,并且一直存在。這個時候累積多了就會導致內(nèi)存泄漏(解決辦法:使用完成后調(diào)用remove方法)磅轻。2. 一個線程可以有多個ThreadLocal珍逸,都會被存在Entry[]數(shù)組中。

  • ThreadLocal初始化賦值瓢省,與當前線程綁定


    初始化賦值

    綁定對應線程

    threadLocals作為Thread類中的一個成員變量弄息,在ThreadLocal進行數(shù)據(jù)賦值初始化時會被賦值,這個時候其實就是將線程與實際數(shù)據(jù)變量進行了綁定勤婚。故摹量,ThreadLocal中的數(shù)據(jù)都是線程隔離的,就不會存在多線程共享變量導致的并發(fā)問題。

  • 子線程如何使用父線程的本地變量
    InheritableThreadLocal實現(xiàn)了子線程使用父線程的變量

// 構造Thread對象時缨称,初始化方法
private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }

        this.name = name;

        Thread parent = currentThread();
        SecurityManager security = System.getSecurityManager();
        if (g == null) {
            /* Determine if it's an applet or not */

            /* If there is a security manager, ask the security manager
               what to do. */
            if (security != null) {
                g = security.getThreadGroup();
            }

            /* If the security doesn't have a strong opinion of the matter
               use the parent thread group. */
            if (g == null) {
                g = parent.getThreadGroup();
            }
        }

        /* checkAccess regardless of whether or not threadgroup is
           explicitly passed in. */
        g.checkAccess();

        /*
         * Do we have the required permissions?
         */
        if (security != null) {
            if (isCCLOverridden(getClass())) {
                security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
            }
        }

        g.addUnstarted();

        this.group = g;
        this.daemon = parent.isDaemon();
        this.priority = parent.getPriority();
        if (security == null || isCCLOverridden(parent.getClass()))
            this.contextClassLoader = parent.getContextClassLoader();
        else
            this.contextClassLoader = parent.contextClassLoader;
        this.inheritedAccessControlContext =
                acc != null ? acc : AccessController.getContext();
        this.target = target;
        setPriority(priority);
        //inheritThreadLocals變量賦值凝果,將父線程的ThreadLocalMap對象賦值給inheritThreadLocals
        if (inheritThreadLocals && parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        /* Stash the specified stack size in case the VM cares */
        this.stackSize = stackSize;

        /* Set thread ID */
        tid = nextThreadID();
    }

4. 應用場景

  • 存儲數(shù)據(jù)庫連接對象:why?為了避免多個線程公用一個連接對象進行數(shù)據(jù)庫操作時相互之間產(chǎn)生影響睦尽。你肯定不想自己查出來的某些結果被其他線程篡改過
  • web服務器净,每次請求的url,參數(shù)等信息打印当凡,并標準線程編號山害,便于后續(xù)排查實際問題。
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末沿量,一起剝皮案震驚了整個濱河市浪慌,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌朴则,老刑警劉巖权纤,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異乌妒,居然都是意外死亡汹想,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門撤蚊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來古掏,“玉大人,你說我怎么就攤上這事拴魄∪呷祝” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵匹中,是天一觀的道長夏漱。 經(jīng)常有香客問我,道長顶捷,這世上最難降的妖魔是什么挂绰? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮服赎,結果婚禮上葵蒂,老公的妹妹穿的比我還像新娘。我一直安慰自己重虑,他們只是感情好践付,可當我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著缺厉,像睡著了一般永高。 火紅的嫁衣襯著肌膚如雪隧土。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天命爬,我揣著相機與錄音曹傀,去河邊找鬼。 笑死饲宛,一個胖子當著我的面吹牛皆愉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播艇抠,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼幕庐,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了练链?” 一聲冷哼從身側響起翔脱,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎媒鼓,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體错妖,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡绿鸣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了暂氯。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片潮模。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖痴施,靈堂內(nèi)的尸體忽然破棺而出擎厢,到底是詐尸還是另有隱情,我是刑警寧澤辣吃,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布动遭,位于F島的核電站,受9級特大地震影響神得,放射性物質(zhì)發(fā)生泄漏厘惦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一哩簿、第九天 我趴在偏房一處隱蔽的房頂上張望宵蕉。 院中可真熱鬧,春花似錦节榜、人聲如沸羡玛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽稼稿。三九已至薄榛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間渺杉,已是汗流浹背蛇数。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留是越,地道東北人耳舅。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像倚评,于是被迫代替她去往敵國和親浦徊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容

  • ThreadLocal提供一個保存線程本地變量的方案天梧。每個線程都能保存它自己的變量盔性,線程之間變量獨立。 又學習到多...
    cafebabe0o0閱讀 368評論 0 3
  • 目前呢岗,多線程編程可以說是在大部分平臺和應用上都需要實現(xiàn)的一個基本需求冕香。本系列文章就來對 Java 平臺下的多線程編...
    業(yè)志陳閱讀 453評論 0 0
  • 當多線程訪問共享可變數(shù)據(jù)時,涉及到線程間同步的問題后豫,并不是所有時候悉尾,都要用到共享數(shù)據(jù),所以就需要線程封閉出場了挫酿。 ...
    武培軒閱讀 115評論 0 0
  • 1) 什么是線程构眯、進程? 進程是程序執(zhí)行時的一個實例早龟,是系統(tǒng)進行資源分配和調(diào)度的一個獨立單位惫霸。線程是進程的一個實體...
    xiaoqunzi233閱讀 1,128評論 0 0
  • 并發(fā)編程是提高程序運行效率與響應速度的重要手段,在多CPU條件下葱弟,并發(fā)編程可以使硬件得到更大程度的運用壹店。由于在并發(fā)...
    東方未曦閱讀 373評論 1 1