欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

深入理解Java中的弱引用

 更新時間:2015年01月16日 10:39:07   投稿:junjie  
這篇文章主要介紹了深入理解Java中的弱引用,本文講解了強(qiáng)引用、弱引用、引用隊(duì)列、四種引用、軟引用、虛引用等內(nèi)容,需要的朋友可以參考下

不久之前,我面試了一些求職Java高級開發(fā)工程師的應(yīng)聘者。我常常會面試他們說,“你能給我介紹一些Java中得弱引用嗎?”,如果面試者這樣說,“嗯,是不是垃圾回收有關(guān)的?”,我就會基本滿意了,我并不期待回答是一篇詰究本末的論文描述。

然而事與愿違,我很吃驚的發(fā)現(xiàn),在將近20多個有著平均5年開發(fā)經(jīng)驗(yàn)和高學(xué)歷背景的應(yīng)聘者中,居然只有兩個人知道弱引用的存在,但是在這兩個人之中只有一個人真正了解這方面的知識。在面試過程中,我還嘗試提示一些東西,來看看有沒有人突然說一聲“原來是這個啊”,結(jié)果很是讓我失望。我開始困惑,為什么這塊的知識如此不被重視,畢竟弱引用是一個很有用途的特性,況且這個特性已經(jīng)在7年前 Java 1.2發(fā)布時便引入了。

好吧,這里我不期待你看完本文之后成為一個弱引用方面的專家,但是我認(rèn)為至少你應(yīng)該了解什么是弱引用,如何使用它們,并且什么場景使用。既然它們是一些不知名的概念,我簡單就著前面的三個問題來說明一下。

強(qiáng)引用(Strong Reference)

強(qiáng)引用就是我們經(jīng)常使用的引用,其寫法如下:

復(fù)制代碼 代碼如下:

StringBuffer buffer = new StringBuffer();

上面創(chuàng)建了一個StringBuffer對象,并將這個對象的(強(qiáng))引用存到變量buffer中。是的,就是這個小兒科的操作(請?jiān)徫疫@樣的說法)。強(qiáng)引用最重要的就是它能夠讓引用變得強(qiáng)(Strong),這就決定了它和垃圾回收器的交互。具體來說,如果一個對象通過一串強(qiáng)引用鏈接可到達(dá)(Strongly reachable),它是不會被回收的。如果你不想讓你正在使用的對象被回收,這就正是你所需要的。

但是強(qiáng)引用如此之強(qiáng)

在一個程序里,將一個類設(shè)置成不可被擴(kuò)展是有點(diǎn)不太常見的,當(dāng)然這個完全可以通過類標(biāo)記成final實(shí)現(xiàn)?;蛘咭部梢愿訌?fù)雜一些,就是通過內(nèi)部包含了未知數(shù)量具體實(shí)現(xiàn)的工廠方法返回一個接口(Interface)。舉個例子,我們想要使用一個叫做Widget的類,但是這個類不能被繼承,所以無法增加新的功能。

但是我們?nèi)绻胱粉橶idget對象的額外信息,我們該怎么辦? 假設(shè)我們需要記錄每個對象的序列號,但是由于Widget類并不包含這個屬性,而且也不能擴(kuò)展導(dǎo)致我們也不能增加這個屬性。其實(shí)一點(diǎn)問題也沒有,HashMap完全可以解決上述的問題。

復(fù)制代碼 代碼如下:

serialNumberMap.put(widget, widgetSerialNumber);

這表面看上去沒有問題,但是widget對象的強(qiáng)引用很有可能會引發(fā)問題。我們可以確信當(dāng)一個widget序列號不需要時,我們應(yīng)該將這個條目從map中移除。如果我們沒有移除的話,可能會導(dǎo)致內(nèi)存泄露,亦或者我們手動移除時刪除了我們正在使用的widgets,會導(dǎo)致有效數(shù)據(jù)的丟失。其實(shí)這些問題很類似,這就是沒有垃圾回收機(jī)制的語言管理內(nèi)存時常遇到的問題。但是我們不用去擔(dān)心這個問題,因?yàn)槲覀兪褂玫臅r具有垃圾回收機(jī)制的Java語言。

另一個強(qiáng)引用可能帶來的問題就是緩存,尤其是像圖片這樣的大文件的緩存。假設(shè)你有一個程序需要處理用戶提供的圖片,通常的做法就是做圖片數(shù)據(jù)緩存,因?yàn)閺拇疟P加載圖片代價(jià)很大,并且同時我們也想避免在內(nèi)存中同時存在兩份一樣的圖片數(shù)據(jù)。

緩存被設(shè)計(jì)的目的就是避免我們?nèi)ピ俅渭虞d哪些不需要的文件。你會很快發(fā)現(xiàn)在緩存中會一直包含一個到已經(jīng)指向內(nèi)存中圖片數(shù)據(jù)的引用。使用強(qiáng)引用會強(qiáng)制圖片數(shù)據(jù)留在內(nèi)存,這就需要你來決定什么時候圖片數(shù)據(jù)不需要并且手動從緩存中移除,進(jìn)而可以讓垃圾回收器回收。因此你再一次被強(qiáng)制做垃圾回收器該做的工作,并且人為決定是該清理到哪一個對象。

弱引用(Weak Reference)

弱引用簡單來說就是將對象留在內(nèi)存的能力不是那么強(qiáng)的引用。使用WeakReference,垃圾回收器會幫你來決定引用的對象何時回收并且將對象從內(nèi)存移除。創(chuàng)建弱引用如下:

復(fù)制代碼 代碼如下:

eakReference<Widget> weakWidget = new WeakReference<Widget>(widget);

使用weakWidget.get()就可以得到真實(shí)的Widget對象,因?yàn)槿跻貌荒茏钃趵厥掌鲗ζ浠厥?,你會發(fā)現(xiàn)(當(dāng)沒有任何強(qiáng)引用到widget對象時)使用get時突然返回null。

解決上述的widget序列數(shù)記錄的問題,最簡單的辦法就是使用Java內(nèi)置的WeakHashMap類。WeakHashMap和HashMap幾乎一樣,唯一的區(qū)別就是它的鍵(不是值!!!)使用WeakReference引用。當(dāng)WeakHashMap的鍵標(biāo)記為垃圾的時候,這個鍵對應(yīng)的條目就會自動被移除。這就避免了上面不需要的Widget對象手動刪除的問題。使用WeakHashMap可以很便捷地轉(zhuǎn)為HashMap或者M(jìn)ap。

引用隊(duì)列(Reference Queue)

一旦弱引用對象開始返回null,該弱引用指向的對象就被標(biāo)記成了垃圾。而這個弱引用對象(非其指向的對象)就沒有什么用了。通常這時候需要進(jìn)行一些清理工作。比如WeakHashMap會在這時候移除沒用的條目來避免保存無限制增長的沒有意義的弱引用。

引用隊(duì)列可以很容易地實(shí)現(xiàn)跟蹤不需要的引用。當(dāng)你在構(gòu)造WeakReference時傳入一個ReferenceQueue對象,當(dāng)該引用指向的對象被標(biāo)記為垃圾的時候,這個引用對象會自動地加入到引用隊(duì)列里面。接下來,你就可以在固定的周期,處理傳入的引用隊(duì)列,比如做一些清理工作來處理這些沒有用的引用對象。

四種引用

Java中實(shí)際上有四種強(qiáng)度不同的引用,從強(qiáng)到弱它們分別是,強(qiáng)引用,軟引用,弱引用和虛引用。上面部分介紹了強(qiáng)引用和弱引用,下面介紹剩下的兩個,軟引用和虛引用。

軟引用(Soft Reference)

軟引用基本上和弱引用差不多,只是相比弱引用,它阻止垃圾回收期回收其指向的對象的能力強(qiáng)一些。如果一個對象是弱引用可到達(dá),那么這個對象會被垃圾回收器接下來的回收周期銷毀。但是如果是軟引用可以到達(dá),那么這個對象會停留在內(nèi)存更時間上長一些。當(dāng)內(nèi)存不足時垃圾回收器才會回收這些軟引用可到達(dá)的對象。

由于軟引用可到達(dá)的對象比弱引用可達(dá)到的對象滯留內(nèi)存時間會長一些,我們可以利用這個特性來做緩存。這樣的話,你就可以節(jié)省了很多事情,垃圾回收器會關(guān)心當(dāng)前哪種可到達(dá)類型以及內(nèi)存的消耗程度來進(jìn)行處理。

虛引用 (Phantom Reference)

與軟引用,弱引用不同,虛引用指向的對象十分脆弱,我們不可以通過get方法來得到其指向的對象。它的唯一作用就是當(dāng)其指向的對象被回收之后,自己被加入到引用隊(duì)列,用作記錄該引用指向的對象已被銷毀。

當(dāng)弱引用的指向?qū)ο笞兊萌跻每傻竭_(dá),該弱引用就會加入到引用隊(duì)列。這一操作發(fā)生在對象析構(gòu)或者垃圾回收真正發(fā)生之前。理論上,這個即將被回收的對象是可以在一個不符合規(guī)范的析構(gòu)方法里面重新復(fù)活。但是這個弱引用會銷毀。虛引用只有在其指向的對象從內(nèi)存中移除掉之后才會加入到引用隊(duì)列中。其get方法一直返回null就是為了阻止其指向的幾乎被銷毀的對象重新復(fù)活。

虛引用使用場景主要由兩個。它允許你知道具體何時其引用的對象從內(nèi)存中移除。而實(shí)際上這是Java中唯一的方式。這一點(diǎn)尤其表現(xiàn)在處理類似圖片的大文件的情況。當(dāng)你確定一個圖片數(shù)據(jù)對象應(yīng)該被回收,你可以利用虛引用來判斷這個對象回收之后在繼續(xù)加載下一張圖片。這樣可以盡可能地避免可怕的內(nèi)存溢出錯誤。

第二點(diǎn),虛引用可以避免很多析構(gòu)時的問題。finalize方法可以通過創(chuàng)建強(qiáng)引用指向快被銷毀的對象來讓這些對象重新復(fù)活。然而,一個重寫了finalize方法的對象如果想要被回收掉,需要經(jīng)歷兩個單獨(dú)的垃圾收集周期。在第一個周期中,某個對象被標(biāo)記為可回收,進(jìn)而才能進(jìn)行析構(gòu)。但是因?yàn)樵谖鰳?gòu)過程中仍有微弱的可能這個對象會重新復(fù)活。這種情況下,在這個對象真實(shí)銷毀之前,垃圾回收器需要再次運(yùn)行。因?yàn)槲鰳?gòu)可能并不是很及時,所以在調(diào)用對象的析構(gòu)之前,需要經(jīng)歷數(shù)量不確定的垃圾收集周期。這就意味著在真正清理掉這個對象的時候可能發(fā)生很大的延遲。這就是為什么當(dāng)大部分堆被標(biāo)記成垃圾時還是會出現(xiàn)煩人的內(nèi)存溢出錯誤。

使用虛引用,上述情況將引刃而解,當(dāng)一個虛引用加入到引用隊(duì)列時,你絕對沒有辦法得到一個銷毀了的對象。因?yàn)檫@時候,對象已經(jīng)從內(nèi)存中銷毀了。因?yàn)樘撘貌荒鼙挥米髯屍渲赶虻膶ο笾厣?,所以其對象會在垃圾回收的第一個周期就將被清理掉。

顯而易見,finalize方法不建議被重寫。因?yàn)樘撘妹黠@地安全高效,去掉finalize方法可以虛擬機(jī)變得明顯簡單。當(dāng)然你也可以去重寫這個方法來實(shí)現(xiàn)更多。這完全看個人選擇。

總結(jié)

我想看到這里,很多人開始發(fā)牢騷了,為什么你要講一個過去十年的老古董API呢,好吧,以我的經(jīng)驗(yàn)看,很多的Java程序員并不是很了解這個知識,我認(rèn)為有一些深入的理解是很必要的,同時我希望大家能從本文中收獲一些東西。

相關(guān)文章

  • Java中CountDownLatch工具類詳細(xì)解析

    Java中CountDownLatch工具類詳細(xì)解析

    這篇文章主要介紹了Java中CountDownLatch工具類詳細(xì)解析,創(chuàng)建CountDownLatch對象時,會傳入一個count數(shù)值,該對象每次調(diào)用countDown()方法會使count?--?,就是count每次減1,需要的朋友可以參考下
    2023-11-11
  • Java面向?qū)ο蟮姆庋b你了解嗎

    Java面向?qū)ο蟮姆庋b你了解嗎

    這篇文章主要為大家詳細(xì)介紹了Java面向?qū)ο蟮姆庋b,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • spring boot自定義log4j2日志文件的實(shí)例講解

    spring boot自定義log4j2日志文件的實(shí)例講解

    下面小編就為大家分享一篇spring boot自定義log4j2日志文件的實(shí)例講解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2017-11-11
  • Java基礎(chǔ)教程之字符流文件讀寫

    Java基礎(chǔ)教程之字符流文件讀寫

    這篇文章主要給大家介紹了關(guān)于Java基礎(chǔ)教程之字符流文件讀寫的相關(guān)資料,,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-07-07
  • Spring?boot?使用QQ郵箱進(jìn)行一個驗(yàn)證登入功能

    Spring?boot?使用QQ郵箱進(jìn)行一個驗(yàn)證登入功能

    這篇文章主要介紹了Spring?boot?使用QQ郵箱進(jìn)行一個驗(yàn)證登入,主要包括qq郵箱開啟權(quán)限和創(chuàng)建發(fā)送驗(yàn)證碼的請求Controller,本文通過示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-10-10
  • Java中final作用于變量、參數(shù)、方法及類該如何處理

    Java中final作用于變量、參數(shù)、方法及類該如何處理

    Java中的final關(guān)鍵字非常重要,它可以應(yīng)用于類、方法以及變量,下面這篇文章主要給大家介紹了關(guān)于Java中final作用于變量、參數(shù)、方法及類該如何處理的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下。
    2017-12-12
  • Spring Cloud Zuul路由網(wǎng)關(guān)服務(wù)過濾實(shí)現(xiàn)代碼

    Spring Cloud Zuul路由網(wǎng)關(guān)服務(wù)過濾實(shí)現(xiàn)代碼

    這篇文章主要介紹了Spring Cloud Zuul路由網(wǎng)關(guān)服務(wù)過濾實(shí)現(xiàn)代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • Java中final,finally,finalize?有什么區(qū)別

    Java中final,finally,finalize?有什么區(qū)別

    這篇文章主要給大家分享的是?Java中final,finally,finalize?到底有什么區(qū)別,文章圍繞final,finally,finalize的相關(guān)資料展開詳細(xì)內(nèi)容,具有一定的參考的價(jià)值,需要的朋友可以參考一下
    2021-11-11
  • 詳解CopyOnWriteArrayList是如何保證線程安全

    詳解CopyOnWriteArrayList是如何保證線程安全

    這篇文章主要為大家介紹了CopyOnWriteArrayList是如何保證線程安全講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • Spring AOP面向切面編程實(shí)現(xiàn)原理方法詳解

    Spring AOP面向切面編程實(shí)現(xiàn)原理方法詳解

    這篇文章主要介紹了Spring AOP面向切面編程實(shí)現(xiàn)原理方法詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08

最新評論