java中的缓存

所谓缓存,就是将程序或系统经常要调用的对象存在内存中,一遍其使用时可以快速调用,不必再去创建新的重复的实例。这样做可以减少系统开销,提高系统效率。

AD:WOT2015 互联网运维与开发者大会 热销抢票

java中的缓存_第1张图片

Cache

所谓缓存,就是将程序或系统经常要调用的对象存在内存中,一遍其使用时可以快速调用,不必再去创建新的重复的实例。这样做可以减少系统开销,提高系统效率。

缓存主要可分为二大类: 

一、通过文件缓存,顾名思义文件缓存是指把数据存储在磁盘上,不管你是以XML格式,序列化文件DAT格式还是其它文件格式;  

二、内存缓存,也就是实现一个类中静态Map,对这个Map进行常规的增删查. 

代码如下 :

 
 
  
  
  
  
  1. package lhm.hcy.guge.frameset.cache; 
  2.  
  3. import java.util.*; 
  4.  
  5.  //Description: 管理缓存 
  6.  
  7.  //可扩展的功能:当chche到内存溢出时必须清除掉最早期的一些缓存对象,这就要求对每个缓存对象保存创建时间 
  8.  
  9. public class CacheManager { 
  10.     private static HashMap cacheMap = new HashMap(); 
  11.  
  12.     //单实例构造方法 
  13.     private CacheManager() { 
  14.         super(); 
  15.     } 
  16.     //获取布尔值的缓存 
  17.     public static boolean getSimpleFlag(String key){ 
  18.         try
  19.             return (Boolean) cacheMap.get(key); 
  20.         }catch(NullPointerException e){ 
  21.             return false
  22.         } 
  23.     } 
  24.     public static long getServerStartdt(String key){ 
  25.         try { 
  26.             return (Long)cacheMap.get(key); 
  27.         } catch (Exception ex) { 
  28.             return 0
  29.         } 
  30.     } 
  31.     //设置布尔值的缓存 
  32.     public synchronized static boolean setSimpleFlag(String key,boolean flag){ 
  33.         if (flag && getSimpleFlag(key)) {//假如为真不允许被覆盖 
  34.             return false
  35.         }else
  36.             cacheMap.put(key, flag); 
  37.             return true
  38.         } 
  39.     } 
  40.     public synchronized static boolean setSimpleFlag(String key,long serverbegrundt){ 
  41.         if (cacheMap.get(key) == null) { 
  42.             cacheMap.put(key,serverbegrundt); 
  43.             return true
  44.         }else
  45.             return false
  46.         } 
  47.     } 
  48.  
  49.  
  50.     //得到缓存。同步静态方法 
  51.     private synchronized static Cache getCache(String key) { 
  52.         return (Cache) cacheMap.get(key); 
  53.     } 
  54.  
  55.     //判断是否存在一个缓存 
  56.     private synchronized static boolean hasCache(String key) { 
  57.         return cacheMap.containsKey(key); 
  58.     } 
  59.  
  60.     //清除所有缓存 
  61.     public synchronized static void clearAll() { 
  62.         cacheMap.clear(); 
  63.     } 
  64.  
  65.     //清除某一类特定缓存,通过遍历HASHMAP下的所有对象,来判断它的KEY与传入的TYPE是否匹配 
  66.     public synchronized static void clearAll(String type) { 
  67.         Iterator i = cacheMap.entrySet().iterator(); 
  68.         String key; 
  69.         ArrayList arr = new ArrayList(); 
  70.         try { 
  71.             while (i.hasNext()) { 
  72.                 java.util.Map.Entry entry = (java.util.Map.Entry) i.next(); 
  73.                 key = (String) entry.getKey(); 
  74.                 if (key.startsWith(type)) { //如果匹配则删除掉 
  75.                     arr.add(key); 
  76.                 } 
  77.             } 
  78.             for (int k = 0; k < arr.size(); k++) { 
  79.                 clearOnly(arr.get(k)); 
  80.             } 
  81.         } catch (Exception ex) { 
  82.             ex.printStackTrace(); 
  83.         } 
  84.     } 
  85.  
  86.     //清除指定的缓存 
  87.     public synchronized static void clearOnly(String key) { 
  88.         cacheMap.remove(key); 
  89.     } 
  90.  
  91.     //载入缓存 
  92.     public synchronized static void putCache(String key, Cache obj) { 
  93.         cacheMap.put(key, obj); 
  94.     } 
  95.  
  96.     //获取缓存信息 
  97.     public static Cache getCacheInfo(String key) { 
  98.  
  99.         if (hasCache(key)) { 
  100.             Cache cache = getCache(key); 
  101.             if (cacheExpired(cache)) { //调用判断是否终止方法 
  102.                 cache.setExpired(true); 
  103.             } 
  104.             return cache; 
  105.         }else 
  106.             return null
  107.     } 
  108.  
  109.     //载入缓存信息 
  110.     public static void putCacheInfo(String key, Cache obj, long dt,boolean expired) { 
  111.         Cache cache = new Cache(); 
  112.         cache.setKey(key); 
  113.         cache.setTimeOut(dt + System.currentTimeMillis()); //设置多久后更新缓存 
  114.         cache.setValue(obj); 
  115.         cache.setExpired(expired); //缓存默认载入时,终止状态为FALSE 
  116.         cacheMap.put(key, cache); 
  117.     } 
  118.     //重写载入缓存信息方法 
  119.     public static void putCacheInfo(String key,Cache obj,long dt){ 
  120.         Cache cache = new Cache(); 
  121.         cache.setKey(key); 
  122.         cache.setTimeOut(dt+System.currentTimeMillis()); 
  123.         cache.setValue(obj); 
  124.         cache.setExpired(false); 
  125.         cacheMap.put(key,cache); 
  126.     } 
  127.  
  128.     //判断缓存是否终止 
  129.     public static boolean cacheExpired(Cache cache) { 
  130.         if (null == cache) { //传入的缓存不存在 
  131.             return false
  132.         } 
  133.         long nowDt = System.currentTimeMillis(); //系统当前的毫秒数 
  134.         long cacheDt = cache.getTimeOut(); //缓存内的过期毫秒数 
  135.         if (cacheDt <= 0||cacheDt>nowDt) { //过期时间小于等于零时,或者过期时间大于当前时间时,则为FALSE 
  136.             return false
  137.         } else { //大于过期时间 即过期 
  138.             return true
  139.         } 
  140.     } 
  141.  
  142.     //获取缓存中的大小 
  143.     public static int getCacheSize() { 
  144.         return cacheMap.size(); 
  145.     } 
  146.  
  147.     //获取指定的类型的大小 
  148.     public static int getCacheSize(String type) { 
  149.         int k = 0
  150.         Iterator i = cacheMap.entrySet().iterator(); 
  151.         String key; 
  152.         try { 
  153.             while (i.hasNext()) { 
  154.                 java.util.Map.Entry entry = (java.util.Map.Entry) i.next(); 
  155.                 key = (String) entry.getKey(); 
  156.                 if (key.indexOf(type) != -1) { //如果匹配则删除掉 
  157.                     k++; 
  158.                 } 
  159.             } 
  160.         } catch (Exception ex) { 
  161.             ex.printStackTrace(); 
  162.         } 
  163.  
  164.         return k; 
  165.     } 
  166.  
  167.     //获取缓存对象中的所有键值名称 
  168.     public static ArrayList getCacheAllkey() { 
  169.         ArrayList a = new ArrayList(); 
  170.         try { 
  171.             Iterator i = cacheMap.entrySet().iterator(); 
  172.             while (i.hasNext()) { 
  173.                 java.util.Map.Entry entry = (java.util.Map.Entry) i.next(); 
  174.                 a.add((String) entry.getKey()); 
  175.             } 
  176.         } catch (Exception ex) {} finally { 
  177.             return a; 
  178.         } 
  179.     } 
  180.  
  181.     //获取缓存对象中指定类型 的键值名称 
  182.     public static ArrayList getCacheListkey(String type) { 
  183.         ArrayList a = new ArrayList(); 
  184.         String key; 
  185.         try { 
  186.             Iterator i = cacheMap.entrySet().iterator(); 
  187.             while (i.hasNext()) { 
  188.                 java.util.Map.Entry entry = (java.util.Map.Entry) i.next(); 
  189.                 key = (String) entry.getKey(); 
  190.                 if (key.indexOf(type) != -1) { 
  191.                     a.add(key); 
  192.                 } 
  193.             } 
  194.         } catch (Exception ex) {} finally { 
  195.             return a; 
  196.         } 
  197.     } 
  198.  
  199.  
  200.  
  201. package lhm.hcy.guge.frameset.cache; 
  202.  
  203. public class Cache { 
  204.         private String key;//缓存ID 
  205.         private Object value;//缓存数据 
  206.         private long timeOut;//更新时间 
  207.         private boolean expired; //是否终止 
  208.         public Cache() { 
  209.                 super(); 
  210.         } 
  211.  
  212.         public Cache(String key, Object value, long timeOut, boolean expired) { 
  213.                 this.key = key; 
  214.                 this.value = value; 
  215.                 this.timeOut = timeOut; 
  216.                 this.expired = expired; 
  217.         } 
  218.  
  219.         public String getKey() { 
  220.                 return key; 
  221.         } 
  222.  
  223.         public long getTimeOut() { 
  224.                 return timeOut; 
  225.         } 
  226.  
  227.         public Object getValue() { 
  228.                 return value; 
  229.         } 
  230.  
  231.         public void setKey(String string) { 
  232.                 key = string; 
  233.         } 
  234.  
  235.         public void setTimeOut(long l) { 
  236.                 timeOut = l; 
  237.         } 
  238.  
  239.         public void setValue(Object object) { 
  240.                 value = object; 
  241.         } 
  242.  
  243.         public boolean isExpired() { 
  244.                 return expired; 
  245.         } 
  246.  
  247.         public void setExpired(boolean b) { 
  248.                 expired = b; 
  249.         } 
  250.  
  251. //测试类, 
  252. class Test { 
  253.     public static void main(String[] args) { 
  254.         System.out.println(CacheManager.getSimpleFlag("alksd")); 
  255. //        CacheManager.putCache("abc", new Cache()); 
  256. //        CacheManager.putCache("def", new Cache()); 
  257. //        CacheManager.putCache("ccc", new Cache()); 
  258. //        CacheManager.clearOnly(""); 
  259. //        Cache c = new Cache(); 
  260. //        for (int i = 0; i < 10; i++) { 
  261. //            CacheManager.putCache("" + i, c); 
  262. //        } 
  263. //        CacheManager.putCache("aaaaaaaa", c); 
  264. //        CacheManager.putCache("abchcy;alskd", c); 
  265. //        CacheManager.putCache("cccccccc", c); 
  266. //        CacheManager.putCache("abcoqiwhcy", c); 
  267. //        System.out.println("删除前的大小:"+CacheManager.getCacheSize()); 
  268. //        CacheManager.getCacheAllkey(); 
  269. //        CacheManager.clearAll("aaaa"); 
  270. //        System.out.println("删除后的大小:"+CacheManager.getCacheSize()); 
  271. //        CacheManager.getCacheAllkey(); 
  272.  
  273.  
  274.     } 
  275. }

java中的本地缓存,工作后陆续用到,一直想写,一直无从下手,最近又涉及到这方面的问题了,梳理了一下。自己构造单例、guava、ehcache基本上涵盖了目前的大多数行为了。
 
为什么要有本地缓存?
在系统中,有些数据,数据量小,但是访问十分频繁(例如国家标准行政区域数据),针对这种场景,需要将数据搞到应用的本地缓存中,以提升系统的访问效率, 减少无谓的数据库访问(数据库访问占用数据库连接,同时网络消耗比较大),但是有一点需要注意,就是缓存的占用空间以及缓存的失效策略。
 
为什么是本地缓存,而不是分布式的集群缓存?
     目前的数据,大多是业务无关的小数据缓存,没有必要搞分布式的集群缓存,目前涉及到订单和商品的数据,会直接走DB进行请求,再加上分布式缓存的构建,集群维护成本比较高,不太适合紧急的业务项目。
     这里介绍一下缓存使用的三个阶段(摘自info架构师文档)
      
 
本地缓存在那个区域?
     目前考虑的是占用了JVM的heap区域,再细化一点的就是heap中的old区,目前的数据量来看,都是一些小数据,加起来没有几百兆,放 在heap区域最快最方便。后期如果需要放置在本地缓存的数据大的时候,可以考虑在off-heap区域(direct-memory 或者 big-memory),但是off-heap区域的话,需要考虑对象的序列化(因为off-heap区域存储的是二进制的数据),另外一个的话就是 off-heap的GC问题。其实,如果真的数据量比较大,那其实就可以考虑搞一个集中式的缓存系统,可以是单机,也可以是集群,来承担缓存的作用。
 
搞一个单例模式,里面有个Map的变量来放置数据
关于单例模式,一个既简单又复杂的模式(http://iamzhongyong.iteye.com/blog/1539642)
非常典型的代码如下:
public class SingletonMap {
  //一个本地的缓存Map
  private Map localCacheStore = new HashMap(); 
 
  //一个私有的对象,非懒汉模式
  private static SingletonMap singletonMap = new SingletonMap(); 
 
  //私有构造方法,外部不可以new一个对象
  private SingletonMap(){
  }  
 
  //静态方法,外部获得实例对象
  public static SingletonMap getInstance(){
    return singletonMap;
  }
 
  //获得缓存中的数据
  public Object getValueByKey(String key){
    return localCacheStore.get(key);
  }
  //向缓存中添加数据
  public void putValue(String key , Object value){
    localCacheStore.put(key, value);
  }
}
这种能不能用?可以用,但是非常局限
但是这种的就是本地缓存了吗?答案显然不是,为啥呢?
1、  没有缓存大小的设置,无法限定缓存体的大小以及存储数据的限制(max size limit);
2、  没有缓存的失效策略(eviction policies);
3、  没有弱键引用,在内存占用吃紧的情况下,JVM是无法回收的(weak rererences keys);
4、  没有监控统计(statistics);
5、  持久性存储(persistent store);
所以,这种就直接废掉了。。。
 
引入EhCache来构建缓存(详细介绍:  http://raychase.iteye.com/blog/1545906)
EhCahce的核心类:
A、CacheManager:Cache的管理类;
B、Cache:具体的cache类信息,负责缓存的get和put等操作
C、CacheConfiguration :cache的配置信息,包含策略、最大值等信息
D、Element:cache中单条缓存数据的单位
典型的代码如下:
public static void main(String[] args) {
    //EhCache的缓存,是通过CacheManager来进行管理的
    CacheManager cacheManager = CacheManager.getInstance();
     
    //缓存的配置,也可以通过xml文件进行
    CacheConfiguration conf = new CacheConfiguration();
    conf.name("cache_name_default");//设置名字
    conf.maxEntriesLocalHeap(1000);//最大的缓存数量
    conf.memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LRU);//设置失效策略
     
    //创建一个缓存对象,并把设置的信息传入进去
    Cache localCache = new Cache(conf);
     
    //将缓存对象添加到管理器中
    cacheManager.addCache(localCache);
         
    localCache.put(new Element("iamzhongyong", new Date()));
     
    System.out.println(localCache.getSize());
    System.out.println(localCache.getStatistics().toString());
    System.out.println(localCache.getName());
    System.out.println(localCache.get("iamzhongyong").toString());
    System.out.println(localCache.get("iamzhongyong").getObjectValue());   
  }
当然,Cache的配置信息,可以通过配置文件制定了。。。
优点:功能强大,有失效策略、最大数量设置等,缓存的持久化只有企业版才有,组件的缓存同步,可以通过jgroup来实现
缺点:功能强大的同时,也使其更加复杂
 
引入guava的cacheBuilder来构建缓存
这个非常强大、简单,通过一个CacheBuilder类就可以满足需求。
缺点就是如果要组件同步的话,需要自己实现这个功能。
典型的代码如下:
public class GuavaCacheBuilderTest {
  public static void main(String[] args) throws Exception{
    GuavaCacheBuilderTest cache = new GuavaCacheBuilderTest();
    cache.getNameLoadingCache("bixiao");
  }
  public void getNameLoadingCache(String name) throws Exception{
    LoadingCache cache = CacheBuilder.newBuilder()     
      .maximumSize(20)//设置大小,条目数     
      .expireAfterWrite(20, TimeUnit.SECONDS)//设置失效时间,创建时间    
      .expireAfterAccess(20, TimeUnit.HOURS) //设置时效时间,最后一次被访问     
      .removalListener(new RemovalListener() { //移除缓存的监听器
        public void onRemoval(RemovalNotification notification) {
          System.out.println("有缓存数据被移除了");
        }})
      .build(new CacheLoader(){ //通过回调加载缓存
        @Override
        public String load(String name) throws Exception {
          return name + "-" + "iamzhongyong";
        }
    });
    System.out.println(cache.get(name));
    //cache.invalidateAll();
  }
}
 
缓存预热怎么搞?
A、全量预热,固定的时间段移除所有,然后再全量预热
适用场景:
1、数据更新不频繁,例如每天晚上3点更新即可的需求;
 2、数据基本没有变化,例如全国区域性数据;
B、增量预热(缓存查询,没有,则查询数据库,有则放入缓存)
适用场景:
1、  数据更新要求缓存中同步更新的场景
 
集群内部,缓存的一致性如何保证?
如果采用ehcache的话,可以使用框架本身的JGroup来实现组内机器之间的缓存同步。
如果是采用google的cacheBuilder的话,需要自己实现缓存的同步。
A、非实时生效数据:数据的更新不会时时发生,应用启动的时候更新即可,然后定时程序定时去清理缓存;
B、需要实时生效数据:启动时可预热也可不预热,但是缓存数据变更后,集群之间需要同步

LRU是Least Recently Used 的缩写,翻译过来就是“最近最少使用”,LRU缓存就是使用这种原理实现,简单的说就是缓存一定量的数据,当超过设定的阈值时就把一些过期的数据删除掉, 比如我们缓存10000条数据,当数据小于10000时可以随意添加,当超过10000时就需要把新的数据添加进来,同时要把过期数据删除,以确保我们最 大缓存10000条,那怎么确定删除哪条过期数据呢,采用LRU算法实现的话就是将最老的数据删掉,废话不多说,下面来说下Java版的LRU缓存实现

Java里面实现LRU缓存通常有两种选择,一种是使用LinkedHashMap,一种是自己设计数据结构,使用链表+HashMap

LRU Cache的LinkedHashMap实现

LinkedHashMap自身已经实现了顺序存储,默认情况下是按照元素的添加顺序存储,也可以启用按照访问顺序存储,即最近读取的数据放在最前 面,最早读取的数据放在最后面,然后它还有一个判断是否删除最老数据的方法,默认是返回false,即不删除数据,我们使用LinkedHashMap实 现LRU缓存的方法就是对LinkedHashMap实现简单的扩展,扩展方式有两种,一种是inheritance,一种是delegation,具体 使用什么方式看个人喜好

复制代码
//LinkedHashMap的一个构造函数,当参数accessOrder为true时,即会按照访问顺序排序,最近访问的放在最前,最早访问的放在后面 public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) { super(initialCapacity, loadFactor); this.accessOrder = accessOrder;
} //LinkedHashMap自带的判断是否删除最老的元素方法,默认返回false,即不删除老数据 //我们要做的就是重写这个方法,当满足一定条件时删除老数据 protected boolean removeEldestEntry(Map.Entry<K,V> eldest) { return false;
}
复制代码

LRU缓存LinkedHashMap(inheritance)实现

采用inheritance方式实现比较简单,而且实现了Map接口,在多线程环境使用时可以使用 Collections.synchronizedMap()方法实现线程安全操作

复制代码
package cn.lzrabbit.structure.lru; import java.util.LinkedHashMap; import java.util.Map; /** * Created by liuzhao on 14-5-15. */ public class LRUCache2<K, V> extends LinkedHashMap<K, V> { private final int MAX_CACHE_SIZE; public LRUCache2(int cacheSize) { super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true);
        MAX_CACHE_SIZE = cacheSize;
    }

    @Override protected boolean removeEldestEntry(Map.Entry eldest) { return size() > MAX_CACHE_SIZE;
    }

    @Override public String toString() {
        StringBuilder sb = new StringBuilder(); for (Map.Entry<K, V> entry : entrySet()) {
            sb.append(String.format("%s:%s ", entry.getKey(), entry.getValue()));
        } return sb.toString();
    }
}
复制代码

 这样算是比较标准的实现吧,实际使用中这样写还是有些繁琐,更实用的方法时像下面这样写,省去了单独见一个类的麻烦

复制代码
final int cacheSize = 100;
Map<String, String> map = new LinkedHashMap<String, String>((int) Math.ceil(cacheSize / 0.75f) + 1, 0.75f, true) {
    @Override protected boolean removeEldestEntry(Map.Entry<String, String> eldest) { return size() > cacheSize;
    }
};
复制代码

 

LRU缓存LinkedHashMap(delegation)实现

delegation方式实现更加优雅一些,但是由于没有实现Map接口,所以线程同步就需要自己搞定了

复制代码
package cn.lzrabbit.structure.lru; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; /** * Created by liuzhao on 14-5-13. */ public class LRUCache3<K, V> { private final int MAX_CACHE_SIZE; private final float DEFAULT_LOAD_FACTOR = 0.75f;
    LinkedHashMap<K, V> map; public LRUCache3(int cacheSize) {
        MAX_CACHE_SIZE = cacheSize; //根据cacheSize和加载因子计算hashmap的capactiy,+1确保当达到cacheSize上限时不会触发hashmap的扩容, int capacity = (int) Math.ceil(MAX_CACHE_SIZE / DEFAULT_LOAD_FACTOR) + 1;
        map = new LinkedHashMap(capacity, DEFAULT_LOAD_FACTOR, true) {
            @Override protected boolean removeEldestEntry(Map.Entry eldest) { return size() > MAX_CACHE_SIZE;
            }
        };
    } public synchronized void put(K key, V value) {
        map.put(key, value);
    } public synchronized V get(K key) { return map.get(key);
    } public synchronized void remove(K key) {
        map.remove(key);
    } public synchronized Set<Map.Entry<K, V>> getAll() { return map.entrySet();
    } public synchronized int size() { return map.size();
    } public synchronized void clear() {
        map.clear();
    }

    @Override public String toString() {
        StringBuilder sb = new StringBuilder(); for (Map.Entry entry : map.entrySet()) {
            sb.append(String.format("%s:%s ", entry.getKey(), entry.getValue()));
        } return sb.toString();
    }
}
复制代码

 LRU Cache的链表+HashMap实现

 注:此实现为非线程安全,若在多线程环境下使用需要在相关方法上添加synchronized以实现线程安全操作

复制代码
package cn.lzrabbit.structure.lru; import java.util.HashMap; /** * Created by liuzhao on 14-5-12. */ public class LRUCache1<K, V> { private final int MAX_CACHE_SIZE; private Entry first; private Entry last; private HashMap<K, Entry<K, V>> hashMap; public LRUCache1(int cacheSize) {
        MAX_CACHE_SIZE = cacheSize;
        hashMap = new HashMap<K, Entry<K, V>>();
    } public void put(K key, V value) {
        Entry entry = getEntry(key); if (entry == null) { if (hashMap.size() >= MAX_CACHE_SIZE) {
                hashMap.remove(last.key);
                removeLast();
            }
            entry = new Entry();
            entry.key = key;
        }
        entry.value = value;
        moveToFirst(entry);
        hashMap.put(key, entry);
    } public V get(K key) {
        Entry<K, V> entry = getEntry(key); if (entry == null) return null;
        moveToFirst(entry); return entry.value;
    } public void remove(K key) {
        Entry entry = getEntry(key); if (entry != null) { if (entry.pre != null) entry.pre.next = entry.next; if (entry.next != null) entry.next.pre = entry.pre; if (entry == first) first = entry.next; if (entry == last) last = entry.pre;
        }
        hashMap.remove(key);
    } private void moveToFirst(Entry entry) { if (entry == first) return; if (entry.pre != null) entry.pre.next = entry.next; if (entry.next != null) entry.next.pre = entry.pre; if (entry == last) last = last.pre; if (first == null || last == null) {
            first = last = entry; return;
        }

        entry.next = first;
        first.pre = entry;
        first = entry;
        entry.pre = null;
    } private void removeLast() { if (last != null) {
            last = last.pre; if (last == null) first = null; else last.next = null;
        }
    } private Entry<K, V> getEntry(K key) { return hashMap.get(key);
    }

    @Override public String toString() {
        StringBuilder sb = new StringBuilder();
        Entry entry = first; while (entry != null) {
            sb.append(String.format("%s:%s ", entry.key, entry.value));
            entry = entry.next;
        } return sb.toString();
    } class Entry<K, V> { public Entry pre; public Entry next; public K key; public V value;
    }
}
复制代码

LinkedHashMap的FIFO实现

FIFO是First Input First Output的缩写,也就是常说的先入先出,默认情况下LinkedHashMap就是按照添加顺序保存,我们只需重写下removeEldestEntry方法即可轻松实现一个FIFO缓存,简化版的实现代码如下

复制代码
final int cacheSize = 5;
LinkedHashMap<Integer, String> lru = new LinkedHashMap<Integer, String>() {
    @Override protected boolean removeEldestEntry(Map.Entry<Integer, String> eldest) { return size() > cacheSize;
    }
};
复制代码

调用示例

测试代码

View Code

运行结果

View Code

 

 

 

注:此文章属懒惰的肥兔原创,版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接

若您觉得这篇文章还不错请点击下右下角的推荐,有了您的支持才能激发作者更大的写作热情,非常感谢。

如有问题,可以通过[email protected]联系我。


你可能感兴趣的:(java中的缓存)