解析ehcache的缓存清除策略

一、内置策略

所谓缓存清除策略,即当缓存空间已满,但又有新的元素要添加到缓存中时,选择清除哪些旧的缓存数据的策略。

ehcache支持3种缓存清除策略,如下所示:

  • FIFO —— 先进先出
    当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有element中,最先被put到cache中的那些element被remove掉。

  • LFU —— Least Frequently Used,最少使用频率。
    基于计数的算法。每个element被put到cache时,都会有一个hitCount成员变量用于计数,初始值为0。每次从cache中get一个element时,该element的hitCount值加1。
    当缓存容量满了,而又需要腾出地方来缓存新的元素时,现有element中,hitCount最小的元素将被remove掉。

  • LRU —— Least Recently Used, 最近最少使用。
    ehcache默认的缓存清除策略。每个element有一个lastAccessTime,当一个element被put到cache时,lastAccessTime被赋为当前时间值。随后每次从cache中get出该element时,lastAccessTime又会被更新为当前时间值。
    当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有element中,lastAccessTime最小的一些元素将被remove掉。

PS:上述3种内置算法都是针对内存缓存(Memory Store),而不针对磁盘缓存(Disk Store)。磁盘缓存只使用LFU算法。
The disk store uses the Least Frequently Used algorithm to evict an element when the store it is full.

二、基本原理

缓存清除策略在ehcache中称为policy,其API接口为Policy,定义如下:

public interface Policy {
    //策略的名称
    String getName();
    //在候选Element中选出一个最应该被移除的element
    Element selectedBasedOnPolicy(Element[] sampledElements, Element justAdded);
    //比较两个element,哪一个更应该被移除
    //返回值为true,表示第2个element优先被移除
    //返回值为false,表示第1个element优先被移除
    boolean compare(Element element1, Element element2);
}

内置策略所对应的类为FifoPolicy, LfuPolicy, LruPolicy。这3个类都不是直接实现Policy,而是继承于AbstractPolicy。
AbstractPolicy是一个抽象类,实现了Policy接口,使用了模板方法设计模式,仅实现selectedBaseOnPolicy()方法。该方法细节如下:

public Element selectedBasedOnPolicy(Element[] sampledElements, Element justAdded) {
   //edge condition when Memory Store configured to size 0
   if (sampledElements.length == 1)
       return sampledElements[0];
   Element lowestElement = null;
   for (Element element : sampledElements)
   {
       if (element == null)
           continue;
       if (lowestElement == null)
       {
           if (!element.equals(justAdded))
               lowestElement = element;
       }
       else if(compare(lowestElement, element) && !element.equals(justAdded))
           lowestElement = element;
   }
   return lowestElement;
}

也就是说,不断调用compare()方法,以选出最应被清除的元素,同时注意把刚加进缓存的元素justAdded排除在外。
那么,分别看一下,FifoPolicy, LfuPolicy, LruPolicy的compare()方法。

public boolean compare(Element element1, Element element2) {
    return element2.getLatestOfCreationAndUpdateTime() < element1.getLatestOfCreationAndUpdateTime();
}

public final long getLatestOfCreationAndUpdateTime() {
    if (0 == lastUpdateTime) {
        return creationTime;
    } else {
        return lastUpdateTime;
    }
}

FIFO策略,比较element的创建先后顺序(中途被update,视为重新创建)。

public boolean compare(Element element1, Element element2) {
    return element2.getHitCount() < element1.getHitCount();
}

LFU策略,比较hitCount计数的大小。

public boolean compare(Element element1, Element element2) {
    return element2.getLastAccessTime() < element1.getLastAccessTime();
}

LRU策略,比较最后一次get的时间戳。

三、自定义策略

除了内置的三种缓存清除策略,ehcache还支持自定义缓存清除策略。从上述解析可看出,自定义策略,其实就是自定义子类,继承AbstractPolicy,并覆写getName和compare两个方法。示例:根据key的长短来清除element。

public class MyPolicy extends AbstractPolicy {
    private static final String NAME = "MY_POLICY";

    public String getName()
    {
        return NAME;
    }

    public boolean compare(Element element1, Element element2)
    {
        String key1 = (String) element1.getObjectKey();
        String key2 = (String) element2.getObjectKey();
        if(key1.compareToIgnoreCase(key2) < 0)
            return false;

        return true;
    }
}

四、设定策略

设置使用哪一种策略,有两种方式:

  • 声明式
    在ehcache.xml的<defaultCache>或<cache>标签中,设置memoryStoreEvictionPolicy属性,其值可为FIFO, LRU, LFU。
    这种方式仅能用于设置内置的三种策略之一。

  • 编程式
    在Java Code中调用Cache的setMemoryStoreEvictionPolicy(Policy policy)方法。
    这种方式可设置自定义的策略,当然也可设置内置的三种策略之一。

    CacheManager cacheManager = CacheManager.newInstance();
    Cache cache = cacheManager.getCache("getPerson");
    cache.setMemoryStoreEvictionPolicy(new MyPolicy());

你可能感兴趣的:(ehcache,缓存,回收)