码迷,mamicode.com
首页 > 编程语言 > 详细

闲来无事,用Java的软引用写了一个山寨的缓存

时间:2015-04-01 11:08:05      阅读:219      评论:0      收藏:0      [点我收藏+]

标签:

闲来无事,用Java的软引用写了一个山寨的缓存

博客分类:
  • java基础
众所周知java中的引用分为 StrongReference、SoftReference、WeakReference、PhantomReference。这几种引用有不同那个的 使用场景,平时我们用的最频繁的也就是StrongReference也就是说形如之这样的引用:

 

Object obj = new Object();

  这种引用就是所谓的强引用,如果此对象没有引用指向它,并且活着的线程无法访问到它(针对垃圾孤岛而言),那么他才会被回收,如果该对象被强引用指向,并且内存被耗尽,抛出OOM垃圾收集器也不会回收该对象。

而对于SoftReference而言它被GC回收的条件就没 那么严格了,如果一个对象当前最强的引用是软引用,并且JVM的内存充足,垃圾回收器是不会回收的该对象的。只有在内存比较吃紧的情况下GC才会回收被软 引用指向的对象,从这个特点我们就看出了软引用可以用来做一些高速缓存,配合LRU策略更好。今天我就自己写一个玩玩。

 

Java代码  技术分享
  1. 代码如下:  
Java代码  技术分享
  1. package com.blackbeans.example;  
  2.   
  3. import java.lang.ref.Reference;  
  4. import java.lang.ref.ReferenceQueue;  
  5. import java.lang.ref.SoftReference;  
  6. import java.util.HashMap;  
  7.   
  8. /** 
  9.  *  
  10.  * @author blackbeans 
  11.  * @param <K> 
  12.  * @param <T> 
  13.  */  
  14. public class ReferenceCache<K,T> {  
  15.       
  16.       
  17.     private HashMap<K, InnerReference<K,T>>  cachedReference = new HashMap<K, InnerReference<K,T>>(1024);  
  18.     private final  ReferenceQueue<T>  referenceQueue ;  
  19.       
  20.     private final ObjectNotFoundHandler<K,T> existsHandler;  
  21.       
  22.     /** 
  23.      * 默认缓存中取不到时的处理器 
  24.      * @author blackbeans 
  25.      * 
  26.      * @param <K> 
  27.      * @param <T> 
  28.      */  
  29.     private static class DefaultObjectNotFoundHandler<K,T> implements ObjectNotFoundHandler<K,T>  
  30.     {  
  31.         @Override  
  32.         public T queryAndCached(K key) {  
  33.             // TODO Auto-generated method stub  
  34.             return null;  
  35.         }  
  36.           
  37.     }  
  38.       
  39.     /** 
  40.      * 缓存中取不到时的处理器 
  41.      * @author blackbeans 
  42.      * 
  43.      * @param <K> 
  44.      * @param <T> 
  45.      */  
  46.     public static interface ObjectNotFoundHandler<K,T>  
  47.     {  
  48.         public T queryAndCached(K key);  
  49.           
  50.     }  
  51.       
  52.       
  53.     private static class InnerReference<K,T> extends SoftReference<T>{  
  54.         private final K key ;  
  55.         public InnerReference(K key,T reference,ReferenceQueue<T> queue) {  
  56.             super(reference,queue);  
  57.             this.key = key;  
  58.         }  
  59.           
  60.         public K getKey()  
  61.         {  
  62.             return this.key;  
  63.         }  
  64.     }   
  65.       
  66.       
  67.     public ReferenceCache(ObjectNotFoundHandler<K,T> handler)  
  68.     {  
  69.         this.referenceQueue = new ReferenceQueue<T>();  
  70.         this.existsHandler = handler == null ? new DefaultObjectNotFoundHandler<K,T>() : handler;  
  71.     }  
  72.       
  73.       
  74.     public ReferenceCache()  
  75.     {  
  76.         this(null);  
  77.     }  
  78.       
  79.     public void cachedReference(K key,T reference)  
  80.     {  
  81.         /** 
  82.          * 清除被软引用的对象并已经被回收的reference 
  83.          */  
  84.         cleanReference(key);  
  85.         if(!this.cachedReference.containsKey(key))  
  86.         {  
  87.             this.cachedReference.put(key, new InnerReference<K,T>(key,reference, this.referenceQueue));  
  88.         }  
  89.     }  
  90.       
  91.     public T getReference(K key)    {  
  92.           
  93.         T obj = null;  
  94.           
  95.         if(this.cachedReference.containsKey(key)){  
  96.             obj =  this.cachedReference.get(key).get();  
  97.         }  
  98.           
  99.         if(null == obj)  
  100.         {  
  101.             /** 
  102.              * 软引用指向的对象被回收,并缓存该软引用 
  103.              */  
  104.             obj = this.existsHandler.queryAndCached(key);  
  105.             this.cachedReference(key, obj);  
  106.             return obj;  
  107.         }  
  108.         return obj;  
  109.           
  110.     }  
  111.   
  112.     @SuppressWarnings("unchecked")  
  113.     private void cleanReference(K key) {  
  114.         //优先检查key对应软引用的对象是否被回收  
  115.         if (this.cachedReference.containsKey(key)  
  116.                 && this.cachedReference.get(key).get() == null)  
  117.             this.cachedReference.remove(key);  
Java代码  技术分享
  1. <span style="white-space: pre;">        </span>T obj = null;  
  2.         //如果当前Key对应的软引用的对象被回收则移除该Key  
  3.         Reference<? extends T> reference = null;  
  4.         while((reference = this.referenceQueue.poll()) != null)  
  5.         {  
  6.             obj = reference.get();  
  7.             if(obj == null)  
  8.             {  
  9.                 this.cachedReference.remove(((InnerReference<K, T>)reference).getKey());  
  10.             }  
  11.         }  
  12.     }  
  13.       
  14.       
  15.     public void clearALLObject()  
  16.     {  
  17.         this.cachedReference.clear();  
  18.         System.gc();  
  19.     }  
  20.       
  21. }  
 

   在整个实现中通过将对象的引用放入我定义的一个 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的软引用写了一个山寨的缓存

标签:

原文地址:http://www.cnblogs.com/langtianya/p/4383175.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!