Reference 和 Reference queue 精髓源碼分析

目錄

  1. Reference 狀態(tài)
    1.1 Active
    1.2 Pending
    1.3 Enqueued
    1.4 Inactive
  2. reference-hannel 線程
    2.1 啟動線程
    2.2 線程執(zhí)行

1.Reference 狀態(tài)

每個Reference狀態(tài)列表是Active瘪松、Pending瓶逃、Enqueued、Inactive (本文也將基于以下這四種狀態(tài)做出源碼解讀)

狀態(tài)間主要的標(biāo)識:
用Reference的成員變量queue與next(類似于單鏈表中的next)來標(biāo)識

ReferenceQueue<? super T> queue;
Reference next; //當(dāng)狀態(tài)不為active,gc自動賦值為this

有了這些約束说庭,GC 只需要檢測next字段就可以知道是否需要對該引用對象(reference)采取特殊處理

  • 如果next為null昼捍,那么說明該引用為Active狀態(tài)
  • 如果next不為null,那么 GC 應(yīng)該按其正常邏輯處理該引用。

什么特殊處理腰素?
GC在狀態(tài)active發(fā)送變化時,會主動把 weakReference中的 reference置null雪营,PhantomReference 中的 reference 無視 (PhantomReference的get方法重寫返回null弓千,可能就因為這原因就沒有置null了),并給next賦值this,以及pending等献起。(別問我為啥洋访,測出來的。谴餐。姻政。。培訓(xùn)出來就這水平了)

1.1 Active

描述:
active 狀態(tài)下的reference會受到GC的特別對待总寒,GC在發(fā)現(xiàn)對象的可達性變成合適的狀態(tài)后將變更reference狀態(tài)扶歪,具體是變更為pending還是Inactive,取決于是否注冊了 queue

特點:

//如果構(gòu)造參數(shù)中沒指定queue摄闸,那么queue為ReferenceQueue.NULL
//否則為構(gòu)造參數(shù)中傳遞過來的queue
queue = ReferenceQueue || ReferenceQueue.NULL
next = null

源碼分析:

Reference(T referent) {
        this(referent, null);
}
Reference(T referent, ReferenceQueue<? super T> queue) {
        this.referent = referent;
        this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
}

1.2 Pending

描述:
pending-Reference列表中的引用都是這個狀態(tài)。
它們等著被內(nèi)部線程ReferenceHandler處理(調(diào)用ReferenceQueue.enqueue方法)
沒有注冊的實例不會進入這個狀態(tài)!

特點:

//ReferenceQueue 是注冊的隊列,從構(gòu)造參數(shù)哪里傳過來的
queue=ReferenceQueue
next = this

源碼分析:

  1. 想進Pending就必須要注冊隊列,ReferenceQueue.NULL 是不會enqueue
 static boolean tryHandlePending(boolean waitForNotify) {
       //some code
        ReferenceQueue<? super Object> q = r.queue;
        if (q != ReferenceQueue.NULL) q.enqueue(r);
        return true;
    }
  1. next=this妹萨,這個應(yīng)該是GC賦的值年枕,只要reference的state一改變,這個next就莫名其妙被賦值了乎完。

3.似乎明白了 ReferenceQueue.ENQUEUED 的含義

public boolean isEnqueued() {
        return (this.queue == ReferenceQueue.ENQUEUED);
    }

1.3 Enqueued

描述:
調(diào)用ReferenceQueue.enqueued方法后的引用處于這個狀態(tài)中熏兄。
沒有注冊的實例不會進入這個狀態(tài)。

特點:

queue = ReferenceQueue.ENQUEUED;
next = queue的下一個引用, 如果已經(jīng)queue是最后一個元素树姨,那么就是自身.

源碼分析:
可以看出 整體是一種先進后出的棧結(jié)構(gòu)摩桶。head作為棧頭。r.next指向成員變量 head帽揪,如果head為null硝清,那么就指向自己(為了后面的壓棧好找元素)

private volatile Reference<? extends T> head = null;
boolean enqueue(Reference<? extends T> r) { 
//some code
            r.queue = ENQUEUED;
            r.next = (head == null) ? r : head;
            head = r;
//some code            
}

1.4 Inactive

描述:
最終狀態(tài),處于這個狀態(tài)的引用對象转晰,狀態(tài)不會在改變芦拿。

兩種途徑到這個狀態(tài):
1.referenceQueue 調(diào)用 reallyPoll ,
2.不注冊 referenceQueue查邢,reference state變化時蔗崎。

特點:

queue = ReferenceQueue.NULL;
next = this

源碼分析:

private Reference<? extends T> reallyPoll() {       /* Must hold lock */
        Reference<? extends T> r = head;
        //some code
            r.queue = NULL;
            r.next = r;
         //some code
    }

2.reference-hannel 線程

2.1啟動線程

  1. 說明jvm一啟動線程就跟著啟動了
  2. 提供了一個 JavaLangRefAccess 來提供外接接口訪問
static {
        ThreadGroup tg = Thread.currentThread().getThreadGroup();
        for (ThreadGroup tgn = tg;
             tgn != null;
             tg = tgn, tgn = tg.getParent());
        Thread handler = new ReferenceHandler(tg, "Reference Handler");
        /* If there were a special system-only priority greater than
         * MAX_PRIORITY, it would be used here
         */
        handler.setPriority(Thread.MAX_PRIORITY);
        handler.setDaemon(true);
        handler.start();

        // provide access in SharedSecrets
        SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {//提供一個訪問接口
            @Override
            public boolean tryHandlePendingReference() {
                return tryHandlePending(false);
            }
        });
    }

2.2 線程執(zhí)行

  1. pending == null 時,會阻塞線程扰藕,所以不會一直調(diào)用缓苛。gc肯定notify了
  2. Cleaner 是個重要的接口,非常適合做資源回收邓深。
  3. 如果注冊了引用隊列未桥,會將引用enqueue進去番官。
static boolean tryHandlePending(boolean waitForNotify) {
        Reference<Object> r;
        Cleaner c;
        try {
            synchronized (lock) {
                if (pending != null) {
                    r = pending;
                    // 'instanceof' might throw OutOfMemoryError sometimes
                    // so do this before un-linking 'r' from the 'pending' chain...
                    c = r instanceof Cleaner ? (Cleaner) r : null;
                    // unlink 'r' from 'pending' chain
                    pending = r.discovered;
                    r.discovered = null;
                } else {
                    // The waiting on the lock may cause an OutOfMemoryError
                    // because it may try to allocate exception objects.
                    if (waitForNotify) {
                        lock.wait();
                    }
                    // retry if waited
                    return waitForNotify;
                }
            }
        } catch (OutOfMemoryError x) {
            // Give other threads CPU time so they hopefully drop some live references
            // and GC reclaims some space.
            // Also prevent CPU intensive spinning in case 'r instanceof Cleaner' above
            // persistently throws OOME for some time...
            Thread.yield();
            // retry
            return true;
        } catch (InterruptedException x) {
            // retry
            return true;
        }

        // Fast path for cleaners
        if (c != null) {
            c.clean();
            return true;
        }

        ReferenceQueue<? super Object> q = r.queue;
        if (q != ReferenceQueue.NULL) q.enqueue(r);
        return true;
    }

引用:
https://liujiacai.net/blog/2015/09/27/java-weakhashmap/#%E5%BC%B1%E5%BC%95%E7%94%A8%EF%BC%88weak-reference%EF%BC%89

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市钢属,隨后出現(xiàn)的幾起案子徘熔,更是在濱河造成了極大的恐慌,老刑警劉巖淆党,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件酷师,死亡現(xiàn)場離奇詭異,居然都是意外死亡染乌,警方通過查閱死者的電腦和手機山孔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來荷憋,“玉大人台颠,你說我怎么就攤上這事±兆” “怎么了串前?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長实蔽。 經(jīng)常有香客問我荡碾,道長,這世上最難降的妖魔是什么局装? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任坛吁,我火速辦了婚禮,結(jié)果婚禮上铐尚,老公的妹妹穿的比我還像新娘拨脉。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著肖油,像睡著了一般。 火紅的嫁衣襯著肌膚如雪匆骗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天誉简,我揣著相機與錄音碉就,去河邊找鬼。 笑死闷串,一個胖子當(dāng)著我的面吹牛瓮钥,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼碉熄,長吁一口氣:“原來是場噩夢啊……” “哼桨武!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起锈津,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤呀酸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后琼梆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體性誉,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年茎杂,在試婚紗的時候發(fā)現(xiàn)自己被綠了错览。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡煌往,死狀恐怖倾哺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情刽脖,我是刑警寧澤羞海,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站曾棕,受9級特大地震影響扣猫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜翘地,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望癌幕。 院中可真熱鬧衙耕,春花似錦、人聲如沸勺远。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽胶逢。三九已至厅瞎,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間初坠,已是汗流浹背和簸。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留碟刺,地道東北人锁保。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親爽柒。 傳聞我的和親對象是個殘疾皇子吴菠,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,792評論 2 345

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

  • ReferenceQueue 引用隊列做葵,在檢測到適當(dāng)?shù)目傻竭_性更改后,垃圾回收器將已注冊的引用對象添加到該隊列中 ...
    tomas家的小撥浪鼓閱讀 36,098評論 10 59
  • 引用的分類 Java 1.2以后心墅,除了普通的引用外酿矢,Java還定義了軟引用、弱引用嗓化、虛引用等概念棠涮。 強引用:GC ...
    劉惜有閱讀 820評論 0 1
  • 感知GC。怎么感知:* 通過get來判斷已經(jīng)被GC(PhantomReference 在任何時候get都是null...
    YDDMAX_Y閱讀 1,830評論 0 4
  • 當(dāng)我們還是學(xué)生的時候刺覆,每天的生活簡單又壓抑严肪。對這樣的感覺談不上滿意或者不滿,因為我們并不知道外面是什么樣的谦屑,光憑想...
    肥木有閱讀 490評論 0 2
  • 我叫小瑤驳糯,我和我的丈夫生活幸福。一直認(rèn)為這樣的幸福會持續(xù)一輩子氢橙≡褪啵可是,就在我懷孕四個月的時候悍手,他突然失蹤了帘睦。我終日...
    胡莘瑤閱讀 287評論 0 0