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

闲来无事,用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. import java.lang.ref.Reference;
  3. import java.lang.ref.ReferenceQueue;
  4. import java.lang.ref.SoftReference;
  5. import java.util.HashMap;
  6. /**
  7. *
  8. * @author blackbeans
  9. * @param <K>
  10. * @param <T>
  11. */
  12. public class ReferenceCache<K,T> {
  13. private HashMap<K, InnerReference<K,T>>  cachedReference = new HashMap<K, InnerReference<K,T>>(1024);
  14. private final  ReferenceQueue<T>  referenceQueue ;
  15. private final ObjectNotFoundHandler<K,T> existsHandler;
  16. /**
  17. * 默认缓存中取不到时的处理器
  18. * @author blackbeans
  19. *
  20. * @param <K>
  21. * @param <T>
  22. */
  23. private static class DefaultObjectNotFoundHandler<K,T> implements ObjectNotFoundHandler<K,T>
  24. {
  25. @Override
  26. public T queryAndCached(K key) {
  27. // TODO Auto-generated method stub
  28. return null;
  29. }
  30. }
  31. /**
  32. * 缓存中取不到时的处理器
  33. * @author blackbeans
  34. *
  35. * @param <K>
  36. * @param <T>
  37. */
  38. public static interface ObjectNotFoundHandler<K,T>
  39. {
  40. public T queryAndCached(K key);
  41. }
  42. private static class InnerReference<K,T> extends SoftReference<T>{
  43. private final K key ;
  44. public InnerReference(K key,T reference,ReferenceQueue<T> queue) {
  45. super(reference,queue);
  46. this.key = key;
  47. }
  48. public K getKey()
  49. {
  50. return this.key;
  51. }
  52. }
  53. public ReferenceCache(ObjectNotFoundHandler<K,T> handler)
  54. {
  55. this.referenceQueue = new ReferenceQueue<T>();
  56. this.existsHandler = handler == null ? new DefaultObjectNotFoundHandler<K,T>() : handler;
  57. }
  58. public ReferenceCache()
  59. {
  60. this(null);
  61. }
  62. public void cachedReference(K key,T reference)
  63. {
  64. /**
  65. * 清除被软引用的对象并已经被回收的reference
  66. */
  67. cleanReference(key);
  68. if(!this.cachedReference.containsKey(key))
  69. {
  70. this.cachedReference.put(key, new InnerReference<K,T>(key,reference, this.referenceQueue));
  71. }
  72. }
  73. public T getReference(K key)    {
  74. T obj = null;
  75. if(this.cachedReference.containsKey(key)){
  76. obj =  this.cachedReference.get(key).get();
  77. }
  78. if(null == obj)
  79. {
  80. /**
  81. * 软引用指向的对象被回收,并缓存该软引用
  82. */
  83. obj = this.existsHandler.queryAndCached(key);
  84. this.cachedReference(key, obj);
  85. return obj;
  86. }
  87. return obj;
  88. }
  89. @SuppressWarnings("unchecked")
  90. private void cleanReference(K key) {
  91. //优先检查key对应软引用的对象是否被回收
  92. if (this.cachedReference.containsKey(key)
  93. && this.cachedReference.get(key).get() == null)
  94. 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. public void clearALLObject()
  14. {
  15. this.cachedReference.clear();
  16. System.gc();
  17. }
  18. }

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

时间: 2024-10-10 10:01:55

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

java之软引用

一.java中的四种引用简介 1.强引用:创建对象的引用,GC抛出OOM也不回收内存 2.软引用:在OOM之前回收内存 3.弱引用:在GC发现之后释放内存 4.虚引用(幽灵引用):使用后就释放 二.软引用的使用 1.用途:软引用是主要用于内存敏感的高速缓存,在jvm报告内存不足之前会清除所有的软引用,这样以来gc就有可能收集软可及的对象,可能解决内存吃紧问题,避免内溢出. 2.引用的选择机制:heap中对象有强可及对象.软可及对象.弱可及对象.虚可及对象和不可到达对象.应用的强弱顺序是强.软.弱

java对象的强引用,软引用,弱引用和虚引用

从JDK1.2版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期.这四种级别由高到低依次为:强引用.软引用.弱引用和虚引用. 1.强引用 以前我们使用的大部分引用实际上都是强引用,这是使用最普遍的引用.如果一个对象具有强引用,那就类似于必不可少的生活用品,垃圾回收器绝不会回收它.当内存空 间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题.一般都是new出来的. Object o=new

Java之强引用、 软引用、 弱引用、虚引用

1.强引用   平时我们编程的时候例如:Object object=new Object():那object就是一个强引用了.如果一个对象具有强引用,那就类似于必不可少的生活用品,垃圾回收器绝不会回收它.当内存空 间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题. 2.软引用(SoftReference)   如果一个对象只具有软引用,那就类似于可有可物的生活用品.如果内存空间足够,垃圾回收器就不会回收它,如果

Java 强引用、 软引用、 弱引用、虚引用

 1.对象的强.软.弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象.也就是说,只有对象处于可触及(reachable)状态,程序才能使用它.从JDK 1.2版本开始,把对象的引用分为4种级别,从而使程序能更加灵活地控制对象的生命周期.这4种级别由高到低依次为:强引用.软引用.弱引用和虚引用.下图为对象应用类层次. ⑴强引用(StrongReference)   强引用是使用最普遍的引用.如果一个对象具有强引用,那垃圾回收器绝不会回收它.当内

[转]Java 的强引用、弱引用、软引用、虚引用

1.强引用(StrongReference) 强引用是使用最普遍的引用.如果一个对象具有强引用,那垃圾回收器绝不会回收它.如下: Object o=new Object(); // 强引用 当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题.如果不使用时,要通过如下方式来弱化引用,如下: o=null; // 帮助垃圾收集器回收此对象 显式地设置o为null,或超出对象的生命周期范围,则gc认为该对象不

Java基础 之软引用、弱引用、虚引用

1.概述 在JDK1.2以前的版本中,当一个对象不被任何变量引用,那么程序就无法再使用这个对象.也就是说,只有对象处于可触及状态,程序才能使用它.这 就像在日常生活中,从商店购买了某样物品后,如果有用,就一直保留它,否则就把它扔到垃圾箱,由清洁工人收走.一般说来,如果物品已经被扔到垃圾箱,想再 把它捡回来使用就不可能了.   但有时候情况并不这么简单,你可能会遇到类似鸡肋一样的物品,食之无味,弃之可惜.这种物品现在已经无用了,保留它会占空间,但是立刻扔掉它也不划算,因 为也许将来还会派用场.对于

java引用 强引用,软引用,弱引用

1)强引用(StrongReference)    强引用是使用最普遍的引用.如果一个对象具有强引用,那垃圾回收器绝不会回收它.当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题. 2)软引用(SoftReference)    如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它:如果内存空间不足了,就会回收这些对象的内存.只要垃圾回收器没有回收它,该对象就可以被程序使用.软引用可用来实现

【转】JAVA四种引用(强引用,弱引用,软引用,虚引用)

转自:http://www.cnblogs.com/gudi/p/6403953.html 1.强引用(StrongReference) 强引用是使用最普遍的引用.如果一个对象具有强引用,那垃圾回收器绝不会回收它.如下: Object o=new Object(); // 强引用 当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题.如果不使用时,要通过如下方式来弱化引用,如下: o=null; // 帮

java中的弱引用软引用和虚引用

在java中的java.lang.ref包中定义了三个引用类,分别是软引用.弱引用.和虚引用.这3个类提供了一种便捷的机制让我们可以和垃圾回收机制交互,同时也为缓存提供了一种机制,那么这三个类导致有什么作用呢? SoftReference: 如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它:如果内存空间不足了,就会回收这些对象的内存.只要垃圾回收器没有回收它,该对象就可以被程序使用.软引用可用来实现内存敏感的高速缓存(下文给出示例). 软引用可以和一个引用队列(Reference