Java中的四種引用強、軟、弱和虛引用,對應的生命周期:強>軟>弱>虛引用.
除強引用外,其他3種引用都需要與ReferenceQueue聯合使用,當引用被垃圾回收機制回收的時候,引用會自動放入ReferenceQueue 中.
WeakReference和SoftReference可以用來做Cashe, 文章第二段引用了Java Eye文章,介紹Google collection的MapMaker方便生成ConcurrentMap, 可以方便的設置map中expireddate的時間,實現cache功能。
1.強引用
??? 本章前文介紹的引用實際上都是強引用,這是使用最普遍的引用。如果一個對象具有強引用,那就類似于必不可少的生活用品,垃圾回收器絕不會回收它。當內存空 間不足,
Java
虛擬機寧愿 拋出OutOfMemoryError錯誤,使程序異常終止,也不會靠隨意回收具有強引用的 對象來解決內存不足問題。
2.軟引用(SoftReference)
??? 如果一個對象只具有軟引用,那就類似于可有可物的生活用品。如果內存空間足夠,垃圾回收器就不會回收它,如果內存空間不足了,就會回收這些對象的內存。只 要垃圾回收器沒有回收它,該對象就可以被程序使用。軟引用可用來實現內存敏感的高速緩存。
軟引用可以和一個引用隊列 (ReferenceQueue)聯合使用,如果軟引用所引用的對象被垃圾回收,
Java
虛擬機就會 把這個軟引用加入 到與之關聯的引用隊列中。
3.弱引用(WeakReference)
??? 如果一個對象只具有弱引用,那就類似于可有可物的生活用品。弱引用與軟引用的區別在于:只具有弱引用的對象擁有更短暫的生命周期。在垃圾回收器線程掃描它 所管轄的內存區域的過程中,一旦發現了只具有弱引用的對象,不管當前內存空間足夠與否,都會回收它的內存。不過,由于垃圾回收器是一個優先級很低的線程, 因此不一定會很快發現那些只具有弱引用的對象。
弱引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果弱引用所引用的對象 被垃圾回收,Java虛擬機就會把這個弱引用加入到與之關聯的引用隊列中。
4.虛引用(PhantomReference)
??? "虛引用"顧名思義,就是形同虛設,與其他幾種引用都不同,虛引用并不會決定對象的生命周期。如果一個對象僅持有虛引用,那么它就和沒有任何引用一樣,在 任何時候都可能被垃圾回收。
虛引用主要用來跟蹤對象被垃圾回收的活動。虛引用與軟引用和弱引用的一個區別在于:虛引用必須和引用隊列 (ReferenceQueue)聯合使用。當垃 圾回收器準備回收一個對象時,如果發現它還有虛引用,就會在回收對象的內存之前,把這個虛引用加入到與之關聯的引用隊列中。程序可以通過判斷引用隊列中是 否已經加入了虛引用,來了解
??? 被引用的對象是否將要被垃圾回收。程序如果發現某個虛引用已經被加入到引用隊列,那么就可以在所引用的對象的內存被回收之前采取必要的行動。
摘錄:JAVA EYE http://www.iteye.com/topic/670414
仔細研究了剛發布1.0版本的Google Collections,被其中的MapMaker震驚,這不就是我夢寐以求的Concurrent Map神器嗎?如果Google Collection在5年前就發布該有多好?!廢話少講,邀請大家一起來觀賞一下什么是MapMaker。
Hashtable太老土啦,線程安全我都用ConcurrentHashMap。什么?現在流行MapMaker?
JDK 1.5引入的ConcurrentHashMap由于其精巧的設計,更高的并發性能,捕獲了大家的心,在并發場景中出場率極高,但隨著深入的使用,很快的 就發現了其中的不足。例如在以Map作為Cache的典型場景中,我們都需要有元素過期的處理,WeakHashMap是這方面的高手,但其在并發方面有 點菜(非線程安全),當我們想讓這兩位大將同時上場的時候,就只能抓耳搔腮了。
Google Collections中的MapMaker融合了Weak Reference,線程安全,高并發性能,異步超時清理,自定義構建元素等強大功能于一身。(注)
常閱讀優秀源代碼的童鞋都知道,一般叫Maker的對象都是Builder模式,而這個MapMaker就是來"Build"Map的,下面的代 碼展示了如何構建一個高并發性能,線程安全的WeakHashMap.
- public ? void ?testWeakKeys()? throws ?Exception?{??
- ????ConcurrentMap<Key,?Value>?map?=? new ?MapMaker()??
- ????????.weakKeys()? //?指定Map保存的Key為 WeakReference機制 ??
- ????????.makeMap();???
- ??
- ????Key?key?=? new ?Key();??
- ????map.put(key,? new ?Value());? //?加 入元素 ??
- ????key?=? null ;? //?key變成 了WeakReference ??
- ??
- ????System.gc(); //?觸發垃圾回收 ??
- ????TimeUnit.SECONDS.sleep(1L);??
- ??
- ????assertTrue(map.isEmpty());? //?map 空了,因為WeakReference被回收 ??
- }??
public void testWeakKeys() throws Exception { ConcurrentMap<Key, Value> map = new MapMaker() .weakKeys() // 指定Map保存的Key為WeakReference機制 .makeMap(); Key key = new Key(); map.put(key, new Value()); // 加入元素 key = null; // key變成了WeakReference System.gc();// 觸發垃圾回收 TimeUnit.SECONDS.sleep(1L); assertTrue(map.isEmpty()); // map空了,因為WeakReference被回收 }
?
是不是夠簡單?他不僅支持WeakKeys,還支持WeakValues。
?
- public ? void ?testWeakValues()? throws ?Exception?{??
- ????ConcurrentMap<Key,?Value>?map?=? new ?MapMaker()??
- ????????.weakValues()? //?指定Map保存的 Value為WeakReference機制 ??
- ????????.makeMap();???
- ??
- ????Key?key?=? new ?Key();??
- ????Value?value?=? new ?Value();??
- ????map.put(key,?value);? //?加入元素 ??
- ????key?=? null ;? //?Key成 了WeakReference ??
- ??????
- ????System.gc(); //?觸發垃圾回收 ??
- ????TimeUnit.SECONDS.sleep(1L);??
- ??????
- ????assertFalse(map.isEmpty());? //?map 里的東西還在,因為Value還是StrongReference ??
- ??????
- ????value?=? null ;? //?這次 value也變成了WeakReference ??
- ??
- ????System.gc();? //?觸發垃圾回收 ??
- ????TimeUnit.SECONDS.sleep(1L);??
- ??
- ????assertTrue(map.isEmpty());? //?map 真空了,因為Value是WeakReference被回收 ??
- }??
public void testWeakValues() throws Exception { ConcurrentMap<Key, Value> map = new MapMaker() .weakValues() // 指定Map保存的Value為WeakReference機制 .makeMap(); Key key = new Key(); Value value = new Value(); map.put(key, value); // 加入元素 key = null; // Key成了WeakReference System.gc();// 觸發垃圾回收 TimeUnit.SECONDS.sleep(1L); assertFalse(map.isEmpty()); // map里的東西還在,因為Value還是StrongReference value = null; // 這次value也變成了WeakReference System.gc(); // 觸發垃圾回收 TimeUnit.SECONDS.sleep(1L); assertTrue(map.isEmpty()); // map真空了,因為Value是WeakReference被回收 }
?
還可以選用SoftKeys,和SoftValues,隨意組合,比只能WeakKey的WeakHashMap擴展性強太多了。
?
再來看看On-demand value computation,自定義構建元素。想象下面的場景,你要為一個查詢學生信息的DAO增加結果緩存,并且結果超過60秒過期,我們可以用裝飾模式結 合MapMaker簡單的實現。
?
- interface ?StudentDao?{??
- ????Information?query(String?name);??
- }??
- ??
- class ?StudentDaoImpl? implements ?StudentDao?{??
- ???? //?真正去查數據庫的實現類?代碼省略 ??
- }??
- //?裝飾器 ??
- class ?CachedStudentDao? implements ?StudentDao?{??
- ???? private ? final ?StudentDao?studentDao;??
- ???? private ? final ?ConcurrentMap<String,?Information>?cache;??
- ??
- ???? private ?CachedStudentDao( final ?StudentDao?studentDao)?{??
- ????????Preconditions.checkNotNull(studentDao,? "studentDao" );??
- ???????? this .studentDao?=?studentDao;??
- ??????????
- ???????? this .cache?=? new ?MapMaker()? //?構建一個?computingMap ??
- ????????????.expiration( 60 ,?TimeUnit.SECONDS)? //?元素60秒過期 ??
- ????????????.makeComputingMap( new ?Function<String,?Information>(){??
- ???????????????? @Override ??
- ???????????????? public ?Information?apply(String?name)?{??
- ???????????????????? return ?studentDao.query(name);??
- ????????????????}??
- ????????????});??
- ???????????? //?傳入匿名Function自定義緩存的初始 化。如果緩存中沒有name對應的數據,則調用真正的dao去數據庫 查找數據,同時緩存結果。 ??
- ????}??
- ??
- ???? @Override ??
- ???? public ?Information?query(String?name)?{??
- ???????? return ?cache.get(name);? //?從computing?cache中取結果 ??
- ????}??
- }??
- ??
- public ? void ?test()?{??
- ????StudentDao?cachedStudentDao?=? new ?CachedStudentDao(studentDaoImpl);??
- ???? //?裝飾了studenDaoImpl的 cachedStudentDao具備了緩存結果的能力。 ??
- }??
interface StudentDao { Information query(String name); } class StudentDaoImpl implements StudentDao { // 真正去查數據庫的實現類 代碼省略 } // 裝飾器 class CachedStudentDao implements StudentDao { private final StudentDao studentDao; private final ConcurrentMap<String, Information> cache; private CachedStudentDao(final StudentDao studentDao) { Preconditions.checkNotNull(studentDao, "studentDao"); this.studentDao = studentDao; this.cache = new MapMaker() // 構建一個 computingMap .expiration(60, TimeUnit.SECONDS) // 元素60秒過期 .makeComputingMap(new Function<String, Information>(){ @Override public Information apply(String name) { return studentDao.query(name); } }); // 傳入匿名Function自定義緩存的初始化。如果緩存中沒有name對應的數據,則調用真正的dao去數據庫查找數據,同時緩存結果。 } @Override public Information query(String name) { return cache.get(name); // 從computing cache中取結果 } } public void test() { StudentDao cachedStudentDao = new CachedStudentDao(studentDaoImpl); // 裝飾了studenDaoImpl的cachedStudentDao具備了緩存結果的能力。 }
?
線程安全,高并發性能,元素過期都實現了,并且代碼很簡潔。多虧了MapMaker,臟活、累活,就交給它啦。不過要注意的是,要遵循 ConcurrentHashMap的規范,其不允許有Null的Key和Value。如果查詢出來的結果可能為Null的,可用簡單的包裝類包裝一下, 這里不給出代碼了。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
