有这么一种应用场景:我们需要定时缓存一些数据,但又不想占用内存太多,所以我们会给缓存设置一定的容量大小,如果缓存的数据超过了设置的容量,就需要删除其中一些数据腾出空间来缓存新的数据。
那问题来了,删除掉哪些数据呢,有三种方案:
1,按存入顺序,删除缓存中最先存入的数据
2,按使用时间,删除最长时间没有使用的数据
3,按使用频率,删除一段时间内访问次数最少的数据
这三种方案就是三种缓存算法,分别为:FIFO(First In,First Out)、LRU(Least Recently Used)、LFU(Least Frequently Used)。
本文使用LinkedHashMap实现FIFO和LRU两种算法。
/**
* 缓存使用容量超过设定的容量,则删除最前面的数据
*/
public class XCache<K, V> {
//默认的缓存大小
private static final int DEFAULT_CACHE_SIZE = 10;
//加载因子,使用容量超过(设定容量*加载因子),就会自动扩容
private static final float DEFAULT_LOAD_FACTOR = 0.75f;
/**
* 缓存模式,默认为FIFO
* FIFO:最新存进来的元素放在后面,优先删除先存入的数据
* LRU:最近调用过的元素放在后面,优先删除最长时间没有使用的数据
*/
private Mode mode = Mode.FIFO;
//缓存容量,默认为10
private int cacheSize = DEFAULT_CACHE_SIZE;
//用来实现缓存
private LinkedHashMap<K, V> map;
//缓存删除监听
private OnRemoveListener<K, V> removeListener;
public XCache() {
this(DEFAULT_CACHE_SIZE);
}
public XCache(int cacheSize) {
this(cacheSize, Mode.FIFO);
}
public XCache(int cacheSize, Mode mode) {
this.mode = mode;
this.cacheSize = cacheSize;
init();
}
public void setMode(Mode mode) {
this.mode = mode;
}
public void setCacheSize(int cacheSize) {
this.cacheSize = cacheSize;
}
public void setRemoveListener(OnRemoveListener<K, V> removeListener) {
this.removeListener = removeListener;
}
private void init() {
map = new LinkedHashMap<K, V>(cacheSize, DEFAULT_LOAD_FACTOR, mode == Mode.FIFO ? false : true) {
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
if (size() > cacheSize && removeListener != null)
removeListener.remove(eldest.getKey(), eldest.getValue());
//设置缓存删除条件
//当缓存容量大于设定容量时,按算法进行删除
return size() > cacheSize;
}
};
}
//把数据放入缓存
public synchronized void put(K key, V value) {
map.put(key, value);
}
//从缓存中读取数据
public synchronized V get(K key) {
return map.get(key);
}
//从缓存中主动删除数据
public synchronized V remove(K key) {
return map.remove(key);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (Map.Entry<K, V> entry : map.entrySet()) {
sb.append(String.format("%s:%s ", entry.getKey(), entry.getValue()));
}
return sb.toString();
}
public enum Mode {
FIFO, LRU;
}
public interface OnRemoveListener<K, V> {
void remove(K key, V value);
}
}
调用示例
public class Test {
public static void main(String[] args) {
XCache<String, Integer> xCache = new XCache<>(10, XCache.Mode.LRU);
xCache.setRemoveListener(new XCache.OnRemoveListener<String, Integer>() {
@Override
public void remove(String key, Integer value) {
System.out.println("remove>>>" + key + "==" + value);
}
});
for (int i = 0; i < 20; i++) {
xCache.put("key" + i, i);
}
//模拟调用
xCache.get("key" + 15);
System.out.println(xCache.toString());
}
}