標籤:
閑來無事,用Java的軟引用寫了一個山寨的緩衝
部落格分類:
眾所周知java中的引用分為 StrongReference、SoftReference、WeakReference、PhantomReference。這幾種引用有不同那個的 使用情境,平時我們用的最頻繁的也就是StrongReference也就是說形如之這樣的引用:
Object obj = new Object();
這種引用就是所謂的強引用,如果此對象沒有引用指向它,並且活著的線程無法訪問到它(針對垃圾孤島而言),那麼他才會被回收,如果該對象被強引用指向,並且記憶體被耗盡,拋出OOM垃圾收集器也不會回收該對象。
而對於SoftReference而言它被GC回收的條件就沒 那麼嚴格了,如果一個對象當前最強的引用是軟引用,並且JVM的記憶體充足,記憶體回收行程是不會回收的該對象的。只有在記憶體比較吃緊的情況下GC才會回收被軟 引用指向的對象,從這個特點我們就看出了軟引用可以用來做一些快取,配合LRU策略更好。今天我就自己寫一個玩玩。
Java代碼
- 代碼如下:
Java代碼
- package com.blackbeans.example;
-
- import java.lang.ref.Reference;
- import java.lang.ref.ReferenceQueue;
- import java.lang.ref.SoftReference;
- import java.util.HashMap;
-
- /**
- *
- * @author blackbeans
- * @param <K>
- * @param <T>
- */
- public class ReferenceCache<K,T> {
-
-
- private HashMap<K, InnerReference<K,T>> cachedReference = new HashMap<K, InnerReference<K,T>>(1024);
- private final ReferenceQueue<T> referenceQueue ;
-
- private final ObjectNotFoundHandler<K,T> existsHandler;
-
- /**
- * 預設緩衝中取不到時的處理器
- * @author blackbeans
- *
- * @param <K>
- * @param <T>
- */
- private static class DefaultObjectNotFoundHandler<K,T> implements ObjectNotFoundHandler<K,T>
- {
- @Override
- public T queryAndCached(K key) {
- // TODO Auto-generated method stub
- return null;
- }
-
- }
-
- /**
- * 緩衝中取不到時的處理器
- * @author blackbeans
- *
- * @param <K>
- * @param <T>
- */
- public static interface ObjectNotFoundHandler<K,T>
- {
- public T queryAndCached(K key);
-
- }
-
-
- private static class InnerReference<K,T> extends SoftReference<T>{
- private final K key ;
- public InnerReference(K key,T reference,ReferenceQueue<T> queue) {
- super(reference,queue);
- this.key = key;
- }
-
- public K getKey()
- {
- return this.key;
- }
- }
-
-
- public ReferenceCache(ObjectNotFoundHandler<K,T> handler)
- {
- this.referenceQueue = new ReferenceQueue<T>();
- this.existsHandler = handler == null ? new DefaultObjectNotFoundHandler<K,T>() : handler;
- }
-
-
- public ReferenceCache()
- {
- this(null);
- }
-
- public void cachedReference(K key,T reference)
- {
- /**
- * 清除被軟引用的對象並已經被回收的reference
- */
- cleanReference(key);
- if(!this.cachedReference.containsKey(key))
- {
- this.cachedReference.put(key, new InnerReference<K,T>(key,reference, this.referenceQueue));
- }
- }
-
- public T getReference(K key) {
-
- T obj = null;
-
- if(this.cachedReference.containsKey(key)){
- obj = this.cachedReference.get(key).get();
- }
-
- if(null == obj)
- {
- /**
- * 軟引用指向的對象被回收,並緩衝該軟引用
- */
- obj = this.existsHandler.queryAndCached(key);
- this.cachedReference(key, obj);
- return obj;
- }
- return obj;
-
- }
-
- @SuppressWarnings("unchecked")
- private void cleanReference(K key) {
- //優先檢查key對應軟引用的對象是否被回收
- if (this.cachedReference.containsKey(key)
- && this.cachedReference.get(key).get() == null)
- this.cachedReference.remove(key);
Java代碼
- <span style="white-space: pre;"> </span>T obj = null;
- //如果當前Key對應的軟引用的對象被回收則移除該Key
- Reference<? extends T> reference = null;
- while((reference = this.referenceQueue.poll()) != null)
- {
- obj = reference.get();
- if(obj == null)
- {
- this.cachedReference.remove(((InnerReference<K, T>)reference).getKey());
- }
- }
- }
-
-
- public void clearALLObject()
- {
- this.cachedReference.clear();
- System.gc();
- }
-
- }
在整個實現中通過將對象的引用放入我定義的一個 key->軟引用map中,然後每次從cache中擷取對象時,首先通過key去查詢map獲得對象的軟引用,若存在則通過軟引用去嘗試擷取對象, 若不存在,軟引用指向的對象被回收,那麼我們就回去調用內建的handler,重建一個對象,並cache該對象的軟引用。
在我的實現中我為使用者提供了一個當對象被回收時的處理handler,企圖來指導使用者通過這個handler來重新構造對象,緩衝對象,靈活性還是挺大的。
不足之處就是,如果軟引用的緩衝能用LRU策略更完美了,再為 LRU提供一個Processor,用於使用者自訂LRU策略。其實很簡單只要將HashMap換成LinkedHashMap去實現 removeEldest方法,並在方法中調用自訂的LRU處理器就OK了。
為了減少開銷,我在每次cache的時候才去清理已經失效的軟引用。也許有人會問為啥有個ReferenceQueue呢?其實是這樣的,在軟引用所引用 的對象被回收以後,試想想對象軟引用的對象是被回收了,但是你又引入了另一個對象SoftReference,帶走一個難道還要再留下一個,所以不會的, 軟引用對象被回收後,這個軟引用本身被添加到了這個queue,等待回收。通過便利這個queue擷取軟引用來一出map中到期的軟引用。
至此,該說的也都說了,不該說的也說了,結尾很突兀,敬請見諒!
轉載:http://blackbeans.iteye.com/blog/1039464
閑來無事,用Java的軟引用寫了一個山寨的緩衝