ThreadLocal使用全解

一、何為ThreadLocal

1、ThreadLocal的含義

ThreadLocal宽堆,即線程變量,是一個以ThreadLocal對象為鍵茸习,任意對象為值的存儲結(jié)構(gòu)畜隶。這個結(jié)構(gòu)被附帶在線程上,也就是說一個線程可以根據(jù)一個ThreadLocal對象查詢到綁定在這個線程上的一個值。

2籽慢、ThreadLocal的實用意義

每個線程擁有自己的局部變量毫無疑問比使用全局變量好浸遗,因為局部的變量只有縣城自己能看見,而不會影響到其他線程嗡综。ThreadLocal本身能被多個線程共享使用乙帮,并且又能達到線程安全的目的。常用的就是get极景、set察净、initialValue等方法。

3盼樟、使用ThreadLocal前你必須知道的

JDK建議將ThreadLocal定義為private static類型氢卡。
ThreadLocal最常用的地方就是為每個線程綁定一個數(shù)據(jù)連接、HTTP請求晨缴、用戶身份信息等译秦,這樣一個線程的所有調(diào)用到的方法都可以非常方便地訪問這些資源。

二击碗、ThreadLocal的使用

1筑悴、創(chuàng)建和初始化ThreadLocal

我們只需直接用new的方式創(chuàng)建ThreadLocal變量,并使用一個泛型參數(shù)指定ThreadLocal的類型稍途。如果ThreadLocal的初始值不被設(shè)定阁吝,它的默認初始值將被設(shè)定為null,如果要更改初始值械拍,我們通常有兩種方法:

  • 使用實現(xiàn)了initialValue的匿名內(nèi)部類
  • 使用ThreadLocal的類方法withInitial()突勇,參數(shù)使用lambda表達式
    這兩種方法都是在new一個ThreadLocal對象時使用。
private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();

 //如果要更改初始值
//方法一 需要一個繼承了ThreadLocal父類,重寫了initialValue方法的類坷虑,用它來創(chuàng)建ThreadLocal類對象
private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>(){      //這里使用匿名內(nèi)部類
    @Override
    protected Integer initialValue() {
        return 200; //初始化的值由null變成200
    }
};

//方法二 使用withIntial方法
private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(()->200);

2甲馋、獲取和設(shè)置ThreadLocal的值

使用get和set方法即可

private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(()->200);
//獲取值
System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get());//get獲取值
//設(shè)置值
threadLocal.set(99);//set設(shè)置值

三、ThreadLocal的一個簡單示例

public class ThreadLocalTest {
    private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(()->1);
    public static void main(String[] args) {
        for(int i=0;i<5;i++){
            new Thread(new MyRun()).start();
        }
    }

    //內(nèi)部類
    public static class MyRun implements Runnable{
        @Override
        public void run() {
            Integer left = threadLocal.get();
            System.out.println(Thread.currentThread().getName()+"得到了-->"+left);
            threadLocal.set(left-1);
            System.out.println(Thread.currentThread().getName()+"還剩下-->"+threadLocal.get());
        }
    }
}

四迄损、ThreadLocal的上下文環(huán)境分析

注意定躏,在ThreadLocal的使用中,get到的值的來源有以下規(guī)律

  • 在構(gòu)造器中試圖get:哪個線程調(diào)用了構(gòu)造器就get到哪個線程的ThreadLocal的值
  • 在run方法中或其調(diào)用的方法中試圖get:get該線程自己的ThreadLocal的值
    以下是一個示例
public class ThreadLocalTest {
    private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(()->1);

    public static void main(String[] args) {
        new Thread(new MyRun()).start();    //如果構(gòu)造器中有讀寫ThreadLocal,這里設(shè)置的是main線程
    }

    //內(nèi)部類
    public static class MyRun implements Runnable{
        public MyRun() {
            //構(gòu)造器是哪里調(diào)用就屬于哪里芹敌。這里是main調(diào)用的共屈,所以設(shè)置和打印的都是main的ThreadLocal的值
            threadLocal.set(100);
            System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get());
        }

        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get());
            //new Thread(new MyRun()).start();    //如果在這里又new一個MyRun對象,就要調(diào)用構(gòu)造器党窜,其中set和get的拗引,就是這里這個線程的ThreadLocal的值
        }
    }
}

五、ThreadLocal和Synchronized的對比

ThreadLocal和Synchronized都是為了解決多線程中相同變量的訪問沖突問題幌衣,不同的點是

  • Synchronized是通過線程等待矾削,犧牲時間來解決訪問沖突
  • ThreadLocal是通過每個線程單獨一份存儲空間壤玫,犧牲空間來解決沖突,并且相比于Synchronized哼凯,ThreadLocal具有線程隔離的效果欲间,只有在線程內(nèi)才能獲取到對應(yīng)的值,線程外則不能訪問到想要的值断部。

正因為ThreadLocal的線程隔離特性猎贴,使他的應(yīng)用場景相對來說更為特殊一些。在android中Looper蝴光、ActivityThread以及AMS中都用到了ThreadLocal她渴。當(dāng)某些數(shù)據(jù)是以線程為作用域并且不同線程具有不同的數(shù)據(jù)副本的時候,就可以考慮采用ThreadLocal蔑祟。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末趁耗,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子疆虚,更是在濱河造成了極大的恐慌苛败,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件径簿,死亡現(xiàn)場離奇詭異罢屈,居然都是意外死亡,警方通過查閱死者的電腦和手機篇亭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進店門缠捌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人暗赶,你說我怎么就攤上這事∷嘁叮” “怎么了蹂随?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長因惭。 經(jīng)常有香客問我岳锁,道長,這世上最難降的妖魔是什么蹦魔? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任激率,我火速辦了婚禮,結(jié)果婚禮上勿决,老公的妹妹穿的比我還像新娘乒躺。我一直安慰自己,他們只是感情好低缩,可當(dāng)我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布嘉冒。 她就那樣靜靜地躺著曹货,像睡著了一般。 火紅的嫁衣襯著肌膚如雪讳推。 梳的紋絲不亂的頭發(fā)上顶籽,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天,我揣著相機與錄音银觅,去河邊找鬼礼饱。 笑死,一個胖子當(dāng)著我的面吹牛究驴,可吹牛的內(nèi)容都是我干的镊绪。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼纳胧,長吁一口氣:“原來是場噩夢啊……” “哼镰吆!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起跑慕,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤万皿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后核行,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體牢硅,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年芝雪,在試婚紗的時候發(fā)現(xiàn)自己被綠了减余。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡惩系,死狀恐怖位岔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情堡牡,我是刑警寧澤抒抬,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站晤柄,受9級特大地震影響擦剑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜芥颈,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一惠勒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧爬坑,春花似錦纠屋、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽肉康。三九已至,卻和暖如春灼舍,著一層夾襖步出監(jiān)牢的瞬間吼和,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工骑素, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留炫乓,地道東北人。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓献丑,卻偏偏與公主長得像末捣,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子创橄,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,527評論 2 349

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