Java中的四種引用以及ReferenceQueue

簡(jiǎn)介:

本文主要介紹JAVA中的四種引用: StrongReference(強(qiáng)引用)惋鸥、SoftReferenc(軟引用)募谎、WeakReferenc(弱引用)、PhantomReference(虛引用)的作用智什。同時(shí)我們還將介紹ReferenceQueue和WeakHashMap的功能和使用示例持灰。

歡迎探討,如有錯(cuò)誤敬請(qǐng)指正

如需轉(zhuǎn)載嗓化,請(qǐng)注明出處 http://www.cnblogs.com/nullzx/

1. JAVA中的四種引用

四種引用中棠涮,軟引用、若引用刺覆、虛引用都需要相關(guān)類來創(chuàng)建严肪。創(chuàng)建的時(shí)候都需要傳遞一個(gè)對(duì)象,然后通過引用的get方法獲取真正的對(duì)象谦屑。

1.1 StrongReference(強(qiáng)引用)

強(qiáng)引用就是我們一般在程序中引用一個(gè)對(duì)象的方式

Object obj = new Object();

obj就是一個(gè)強(qiáng)引用驳糯。垃圾回收器絕不會(huì)回收它,當(dāng)內(nèi)存空間不足氢橙,Java虛擬機(jī)寧愿拋出OutOfMemoryError錯(cuò)誤酝枢,使程序異常終止,也不會(huì)靠回收具有強(qiáng)引用的對(duì)象來解決內(nèi)存不足的問題悍手。

SoftReference(軟引用)

軟引用的創(chuàng)建要借助于java.lang.ref包下的SoftReferenc類帘睦。當(dāng)JVM進(jìn)行垃圾回收時(shí),只有在內(nèi)存不足的時(shí)候JVM才會(huì)回收僅有軟引用指向的對(duì)象所占的空間坦康。

軟引用的創(chuàng)建要借助于java.lang.ref包下的SoftReferenc類竣付。當(dāng)JVM進(jìn)行垃圾回收時(shí),只有在內(nèi)存不足的時(shí)候JVM才會(huì)回收僅有軟引用指向的對(duì)象所占的空間滞欠。

package javalearning;
 
import java.lang.ref.SoftReference;
/*
 * 虛擬機(jī)參數(shù)配置
 * -Xms256m
 * -Xmx1024m
*/
public class SoftReferenceDemo {
    public static void main(String[] args){
         
        /*軟引用對(duì)象中指向了一個(gè)長(zhǎng)度為300000000個(gè)元素的整形數(shù)組*/
        SoftReference<int[]> softReference = 
                new SoftReference<int[]>(new int[300000000]);
         
        /*主動(dòng)調(diào)用一次gc,由于此時(shí)JVM的內(nèi)存夠用古胆,此時(shí)softReference引用的對(duì)象未被回收*/
        System.gc();
        System.out.println(softReference.get());
         
        /*消耗內(nèi)存,會(huì)導(dǎo)致一次自動(dòng)的gc,此時(shí)JVM的內(nèi)存不夠用
         *就回收softReference對(duì)象中指向的數(shù)組對(duì)象*/
        int[] strongReference = new int[100000000];
         
        System.out.println(softReference.get());
    }
}

我們應(yīng)該注意到,上面的代碼中名為softReference的引用指向了一個(gè)
SoftReference對(duì)象筛璧,這個(gè)指向還是一個(gè)強(qiáng)引用類型逸绎。而SoftReference對(duì)象中指向int類型數(shù)組的引用就是一個(gè)軟引用類型了惹恃。

運(yùn)行結(jié)果

[I@2a139a55
null

1.3 WeakReference(弱引用)

弱引用的創(chuàng)建要借助于java.lang.ref包下的WeakReferenc類。當(dāng)JVM進(jìn)行垃圾回收時(shí)棺牧,無論內(nèi)存是否充足巫糙,都會(huì)回收僅被弱引用關(guān)聯(lián)的對(duì)象。由于垃圾回收器是一個(gè)優(yōu)先級(jí)很低的線程陨帆,因此不一定會(huì)很快發(fā)現(xiàn)那些被弱引用指向的對(duì)象曲秉。

package javalearning;
 
import java.lang.ref.WeakReference;
 
public class WeakReferenceDemo {
    public static void main(String[] args){
 
        /*若引用對(duì)象中指向了一個(gè)長(zhǎng)度為1000個(gè)元素的整形數(shù)組*/
        WeakReference<String[]> weakReference = 
                new WeakReference<String[]>(new String[1000]);
         
        /*未執(zhí)行g(shù)c,目前僅被弱引用指向的對(duì)象還未被回收,所以結(jié)果不是null*/     
        System.out.println(weakReference.get());
         
        /*執(zhí)行一次gc,即使目前JVM的內(nèi)存夠用,但還是回收僅被弱引用指向的對(duì)象*/
        System.gc();
        System.out.println(weakReference.get());
    }
}

同理疲牵,上面的代碼中名為weakReference的引用指向了一個(gè)
WeakReference對(duì)象承二,這個(gè)指向還是一個(gè)強(qiáng)引用類型。而WeakReference對(duì)象中指向String類型數(shù)組的引用就是一個(gè)弱引用類型了纲爸。

運(yùn)行結(jié)果

[Ljava.lang.String;@2a139a55
null

1.4 PlantomReference(虛引用)

如果一個(gè)對(duì)象僅持有虛引用亥鸠,那么它就和沒有任何引用一樣,在任何時(shí)候都可能被垃圾回收识啦。創(chuàng)建一個(gè)虛引用對(duì)象時(shí)必須還要傳遞一個(gè)引用隊(duì)列(ReferenceQueue)负蚊。

2. ReferenceQueue(引用隊(duì)列)簡(jiǎn)介

當(dāng)gc(垃圾回收線程)準(zhǔn)備回收一個(gè)對(duì)象時(shí),如果發(fā)現(xiàn)它還僅有軟引用(或弱引用颓哮,或虛引用)指向它家妆,就會(huì)在回收該對(duì)象之前,把這個(gè)軟引用(或弱引用冕茅,或虛引用)加入到與之關(guān)聯(lián)的引用隊(duì)列(ReferenceQueue)中伤极。如果一個(gè)軟引用(或弱引用,或虛引用)對(duì)象本身在引用隊(duì)列中姨伤,就說明該引用對(duì)象所指向的對(duì)象被回收了哨坪。

當(dāng)軟引用(或弱引用,或虛引用)對(duì)象所指向的對(duì)象被回收了乍楚,那么這個(gè)引用對(duì)象本身就沒有價(jià)值了当编,如果程序中存在大量的這類對(duì)象(注意,我們創(chuàng)建的軟引用徒溪、弱引用忿偷、虛引用對(duì)象本身是個(gè)強(qiáng)引用,不會(huì)自動(dòng)被gc回收)臊泌,就會(huì)浪費(fèi)內(nèi)存鲤桥。因此我們這就可以手動(dòng)回收位于引用隊(duì)列中的引用對(duì)象本身。

除了上面代碼展示的創(chuàng)建引用對(duì)象的方式缺虐。軟芜壁、弱礁凡、虛引用的創(chuàng)建還有另一種方式高氮,即在創(chuàng)建引用的同時(shí)關(guān)聯(lián)一個(gè)引用隊(duì)列慧妄。

SoftReference(T referent, ReferenceQueue<? super T> q)
 
WeakReference(T referent, ReferenceQueue<? super T> q)
 
PhantomReference(T referent, ReferenceQueue<? super T> q)

下面的示例中我們利用ReferenceQueue回收SoftReference對(duì)象本身。

package javalearning;
 
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
 
public class ReferenceQueneDemo {
     
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static void main(String[] args){
        /*創(chuàng)建引用隊(duì)列*/
        ReferenceQueue<SoftReference<int[]>> rq = 
                new ReferenceQueue<SoftReference<int[]>>();
         
        /*創(chuàng)建一個(gè)軟引用數(shù)組剪芍,每一個(gè)對(duì)象都是軟引用類型*/
        SoftReference<int[]>[] srArr = new SoftReference[1000];
         
        for(int i = 0; i < srArr.length; i++){
            srArr[i] = new SoftReference(new int[300000], rq);
        }
         
        /*(可能)在gc前保留下了三個(gè)強(qiáng)引用*/
        int[] arr1 = srArr[30].get();
        int[] arr2 = srArr[60].get();
        int[] arr3 = srArr[90].get();
         
        /*占用內(nèi)存塞淹,會(huì)導(dǎo)致一次gc,使得只有軟引用指向的對(duì)象被回收*/
        int[] strongRef = new int[200000000];
         
        Object x;
        int n = 0;
        while((x = rq.poll()) != null){
            int idx = 0;
            while(idx < srArr.length){
                if(x == srArr[idx]){
                    System.out.println("free " + x);
                    srArr[idx] = null; /*手動(dòng)釋放內(nèi)存*/
                    n++;
                    break;
                }
                idx++;
            }
        }
         
        /*當(dāng)然最簡(jiǎn)單的方法是通過isEnqueued()判斷一個(gè)軟引用方法是否在
         * 隊(duì)列中罪裹,上面的方法只是舉例
         int n = 0;
         for(int i = 0; i < srArr.length; i++){
            if(srArr[i].isEnqueued()){
                srArr[i] = null;
                n++;
            }
         }  
        */     
        System.out.println("recycle  " + n + "  SoftReference Object");
    }
}

運(yùn)行結(jié)果(省略部分結(jié)果)

……
……
……
free java.lang.ref.SoftReference@cc285f4
free java.lang.ref.SoftReference@55f3ddb1
free java.lang.ref.SoftReference@8bd1b6a
free java.lang.ref.SoftReference@18be83e4
free java.lang.ref.SoftReference@cb5822
recycle  997  SoftReference Object

從上面的例子中可以看出饱普,我們回收SoftReference對(duì)象的效率并不高。原因是每從隊(duì)列中取出一個(gè)SoftReference引用状共,就是我們必須和SoftReference[]數(shù)組中的每一個(gè)對(duì)象逐個(gè)比較套耕。這樣的查找方式顯然不及HashMap,所以我們自然想到構(gòu)建一個(gè)引用類型的HashMap來解決這個(gè)問題峡继。而實(shí)際上JDK中已經(jīng)提供了一個(gè)具有這樣功能的類冯袍,即WeakHashMap。

原文

https://www.cnblogs.com/nullzx/p/7406151.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末碾牌,一起剝皮案震驚了整個(gè)濱河市康愤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌舶吗,老刑警劉巖征冷,帶你破解...
    沈念sama閱讀 221,406評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異誓琼,居然都是意外死亡检激,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門踊赠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來呵扛,“玉大人,你說我怎么就攤上這事筐带〗翊” “怎么了?”我有些...
    開封第一講書人閱讀 167,815評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵伦籍,是天一觀的道長(zhǎng)蓝晒。 經(jīng)常有香客問我,道長(zhǎng)帖鸦,這世上最難降的妖魔是什么芝薇? 我笑而不...
    開封第一講書人閱讀 59,537評(píng)論 1 296
  • 正文 為了忘掉前任将鸵,我火速辦了婚禮仰挣,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘妹沙。我一直安慰自己,他們只是感情好晾嘶,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,536評(píng)論 6 397
  • 文/花漫 我一把揭開白布妓雾。 她就那樣靜靜地躺著,像睡著了一般垒迂。 火紅的嫁衣襯著肌膚如雪械姻。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,184評(píng)論 1 308
  • 那天机断,我揣著相機(jī)與錄音楷拳,去河邊找鬼。 笑死吏奸,一個(gè)胖子當(dāng)著我的面吹牛欢揖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播奋蔚,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼浸颓,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了旺拉?” 一聲冷哼從身側(cè)響起产上,我...
    開封第一講書人閱讀 39,668評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蛾狗,沒想到半個(gè)月后晋涣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,212評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡沉桌,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,299評(píng)論 3 340
  • 正文 我和宋清朗相戀三年谢鹊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片留凭。...
    茶點(diǎn)故事閱讀 40,438評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡佃扼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蔼夜,到底是詐尸還是另有隱情兼耀,我是刑警寧澤,帶...
    沈念sama閱讀 36,128評(píng)論 5 349
  • 正文 年R本政府宣布求冷,位于F島的核電站瘤运,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏匠题。R本人自食惡果不足惜拯坟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,807評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望韭山。 院中可真熱鬧郁季,春花似錦冷溃、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至塞琼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間禁舷,已是汗流浹背彪杉。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留牵咙,地道東北人派近。 一個(gè)月前我還...
    沈念sama閱讀 48,827評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像洁桌,于是被迫代替她去往敵國和親渴丸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,446評(píng)論 2 359

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