Java-ThreadLocal虛引用取值問題分析

Threadlocal是為了,解決多線程環(huán)境下變量隔離的問題;

ThreadLocalMap

是threadLocal用來存儲數(shù)據(jù)的內(nèi)部類罢缸,他沒有實現(xiàn)任何集合接口矮冬,因為它僅供內(nèi)部使用豁鲤;
他是在threadLocal定義的,但是它的實例是在thread類中,是為每一個線程創(chuàng)建了一個Map而不是共享的map;
內(nèi)部定義了一個Entry玖详,key為ThreaLocal,value為存的值勤讽,對key使用了虛引用蟋座;

static class Entry extends WeakReference<ThreadLocal> {
            /** The value associated with this ThreadLocal. */
            Object value;

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

這里就是今天要探討的問題,之前一直卡在這個虛引用(虛引用垃圾回收條件是脚牍,回收時只要發(fā)現(xiàn)是虛引用就會直接回收掉)向臀,因為垃圾回收機制的存在我的第一個疑問是:
1、在線程運行時莫矗,會不會存在這個變量我放在threadLocal里面了飒硅,但是還沒使用然后垃圾回收運行,因為是key是虛引用所以被回收掉作谚,直白的說就是這個值我還沒用就被回收掉了三娩?
這個問題我查閱虛引用的資料了解到,一個對象是可以同時存在虛引用和強引用的妹懒,所以在作用域內(nèi)ThreadLocal的key存在強引用就不會被回收(ThreadLocalMap的key存放的是ThreadLocal對象雀监,而ThreadLocal使用時會new也就是強引用),見下面代碼

public class WeakReferenceDemo {
    static WeakReference<String> weake;

    public static void main(String[] args) {
        test();
        System.out.println("方法外====GC==========前");
        System.out.println("獲取的值-" + weake.get());
        System.gc();//已經(jīng)跳出了test的作用域眨唬,所以對象會被回收
        System.out.println("方法外====GC==========后");
        System.out.println("獲取的值-" + weake.get());

    }

    public static void test() {
        String str = new String("weak_refrence");
        weake = new WeakReference<String>(str);
        System.out.println("方法里====GC==========前");
        System.out.println("獲取的值-" + weake.get());
        System.gc();//這個test方法的作用域里還存在str這個強引用会前,所以不會被回收;
        System.out.println("方法里====GC==========后");
        System.out.println("獲取的值-" + weake.get());
    }
}

輸出結(jié)果:

方法里====GC==========前
獲取的值-weak_refrence
方法里====GC==========后
獲取的值-weak_refrence
方法外====GC==========前
獲取的值-weak_refrence
方法外====GC==========后
獲取的值-null

在threadLocal里面亦是如此匾竿,所以不會存在還沒使用就被回收的情況瓦宜,隨之而來的是下面的問題;
2岭妖、既然回收和作用域有關(guān)系临庇,那么我把這個強引用聲明為全局的是不是這個變量就一直存在了呢?見下面代碼:

public class ThreadLocalDemo01 {
    //把ThreadLocal聲明為全局昵慌,保證他的生命周期在外部使用時還存活
    static ThreadLocal<Integer> intThread = new ThreadLocal<>();
    static ThreadLocal<String> strThread = new ThreadLocal<>();

    public static void main(String[] args) {
                 //使用線程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 100, TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(5));
        int threadNum = 10;
                 //使用計數(shù)器假夺,使線程同步發(fā)生
        CountDownLatch latch = new CountDownLatch(threadNum);
        for (int i = 0; i < threadNum; i++) {
            Thread t = new Thread(new RunableDemo01(latch));
            executor.execute(t);
        }
        try {
            latch.await();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        executor.shutdown();
        System.out.println(intThread.get());//代碼1
        System.out.println(strThread.get());//代碼2
    }
}

class RunableDemo01 implements Runnable {
    private CountDownLatch latch;
    static Integer num = 1;
    static String str = new String();

    public RunableDemo01(CountDownLatch latch) {
        this.latch = latch;
    }

    @Override
    public void run() {
        method();
        latch.countDown();
        System.gc();
        System.out.println();
    }

    public void method() {

        ThreadLocalDemo01.intThread.set(num);
        int n = ThreadLocalDemo01.intThread.get();
        n++;
        ThreadLocalDemo01.strThread.set(str);
        String s = ThreadLocalDemo01.strThread.get();
        s = Thread.currentThread().getName();
        // System.out.println(n);
        // System.out.println(s);
    }

}

上面的代碼把threadLocal聲明為全局的,那么這個強引用在代碼1斋攀、2處應(yīng)該還是存在的已卷,所以就不會被垃圾回收機制處理掉;執(zhí)行代碼:

null
null

結(jié)果為null淳蔼,沒有取到值侧蘸,被回收呢?
確實是被回收了肖方,但是不是因為虛引用的問題被回收闺魏,而是整個map被回收了,原因分析:
這個問題之所以會出現(xiàn)俯画,其實是沒有好好理解ThreadLocal的源碼問題析桥,之前介紹了ThreadLocalMap它是定義在ThreadLocal里面的但是是在Thread里面實例的,所以他的生命周期是和線程相同的艰垂,因為在代碼1泡仗、2處已經(jīng)到了主線程了,而我們放值的時候是在子線程猜憎,1娩怎、2處子線程已經(jīng)結(jié)束,那么他們的ThreadLocalMap也已經(jīng)失效被回收了胰柑,主線程ThreadLocalMap有沒有放入這值所以返回null截亦;
以上就是目前對于Thread的探討爬泥,發(fā)現(xiàn)新問題將繼續(xù)加推。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末崩瓤,一起剝皮案震驚了整個濱河市袍啡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌却桶,老刑警劉巖境输,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異颖系,居然都是意外死亡嗅剖,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進店門嘁扼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來信粮,“玉大人,你說我怎么就攤上這事趁啸〗海” “怎么了?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵莲绰,是天一觀的道長欺旧。 經(jīng)常有香客問我,道長蛤签,這世上最難降的妖魔是什么辞友? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮震肮,結(jié)果婚禮上称龙,老公的妹妹穿的比我還像新娘。我一直安慰自己戳晌,他們只是感情好鲫尊,可當我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著沦偎,像睡著了一般疫向。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上豪嚎,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天搔驼,我揣著相機與錄音,去河邊找鬼侈询。 笑死舌涨,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的扔字。 我是一名探鬼主播囊嘉,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼温技,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了扭粱?” 一聲冷哼從身側(cè)響起荒揣,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎焊刹,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恳蹲,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡虐块,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了嘉蕾。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贺奠。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖错忱,靈堂內(nèi)的尸體忽然破棺而出儡率,到底是詐尸還是另有隱情,我是刑警寧澤以清,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布儿普,位于F島的核電站,受9級特大地震影響掷倔,放射性物質(zhì)發(fā)生泄漏眉孩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一勒葱、第九天 我趴在偏房一處隱蔽的房頂上張望浪汪。 院中可真熱鬧,春花似錦凛虽、人聲如沸死遭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽呀潭。三九已至,卻和暖如春至非,著一層夾襖步出監(jiān)牢的瞬間蜗侈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工睡蟋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留踏幻,地道東北人。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓戳杀,卻偏偏與公主長得像该面,于是被迫代替她去往敵國和親夭苗。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,685評論 2 360

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