自定义缓存
程序员文章站
2022-05-19 15:40:26
...
前言
先来说一下自定义缓存的实现思路,首先需要定义一个存放缓存值的实体类,这个类里包含了缓存的相关信息,比如缓存的 key 和 value,缓存的存入时间、最后使用时间和命中次数(预留字段,用于支持 LFU 缓存淘汰),再使用 ConcurrentHashMap 保存缓存的 key 和 value 对象(缓存值的实体类),然后再新增一个缓存操作的工具类,用于添加和删除缓存,最后再缓存启动时,开启一个无限循环的线程用于检测并删除过期的缓存,实现代码如下。
1、首先,定义一个缓存值实体类,代码如下:
import lombok.Getter;
import lombok.Setter;
/**
* 缓存实体类
*/
@Getter
@Setter
public class CacheValue implements Comparable<CacheValue> {
// 缓存键
private Object key;
// 缓存值
private Object value;
// 最后访问时间
private long lastTime;
// 创建时间
private long writeTime;
// 存活时间
private long expireTime;
// 命中次数
private Integer hitCount;
@Override
public int compareTo(CacheValue o) {
return hitCount.compareTo(o.hitCount);
}
}
2、定义过期缓存检测类的代码如下:
import java.util.concurrent.TimeUnit;
/**
* 过期缓存检测线程
*/
public class ExpireThread implements Runnable {
@Override
public void run() {
while (true) {
try {
// 每十秒检测一次
TimeUnit.SECONDS.sleep(10);
// 缓存检测和清除的方法
expireCache();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 缓存检测和清除的方法
*/
private void expireCache() {
System.out.println("检测缓存是否过期缓存");
for (String key : CacheGlobal.concurrentMap.keySet()) {
MyCache cache = CacheGlobal.concurrentMap.get(key);
// 当前时间 - 写入时间
long timoutTime = TimeUnit.NANOSECONDS.toSeconds(
System.nanoTime() - cache.getWriteTime());
if (cache.getExpireTime() > timoutTime) {
// 没过期
continue;
}
// 清除过期缓存
CacheGlobal.concurrentMap.remove(key);
}
}
}
3、接着,我们要新增一个缓存操作的工具类,用于查询和存入缓存,实现代码如下:
import org.apache.commons.lang3.StringUtils;
import java.util.concurrent.TimeUnit;
/**
* 缓存操作工具类
*/
public class CacheUtils {
/**
* 添加缓存
* @param key
* @param value
* @param expire
*/
public void put(String key, Object value, long expire) {
// 非空判断,借助 commons-lang3
if (StringUtils.isBlank(key)) return;
// 当缓存存在时,更新缓存
if (CacheGlobal.concurrentMap.containsKey(key)) {
MyCache cache = CacheGlobal.concurrentMap.get(key);
cache.setHitCount(cache.getHitCount() + 1);
cache.setWriteTime(System.currentTimeMillis());
cache.setLastTime(System.currentTimeMillis());
cache.setExpireTime(expire);
cache.setValue(value);
return;
}
// 创建缓存
MyCache cache = new MyCache();
cache.setKey(key);
cache.setValue(value);
cache.setWriteTime(System.currentTimeMillis());
cache.setLastTime(System.currentTimeMillis());
cache.setHitCount(1);
cache.setExpireTime(expire);
CacheGlobal.concurrentMap.put(key, cache);
}
/**
* 获取缓存
* @param key
* @return
*/
public Object get(String key) {
// 非空判断
if (StringUtils.isBlank(key)) return null;
// 字典中不存在
if (CacheGlobal.concurrentMap.isEmpty()) return null;
if (!CacheGlobal.concurrentMap.containsKey(key)) return null;
MyCache cache = CacheGlobal.concurrentMap.get(key);
if (cache == null) return null;
// 惰性删除,判断缓存是否过期
long timoutTime = TimeUnit.NANOSECONDS.toSeconds(
System.nanoTime() - cache.getWriteTime());
// 缓存过期
if (cache.getExpireTime() <= timoutTime) {
// 清除过期缓存
CacheGlobal.concurrentMap.remove(k
return null;
}
cache.setHitCount(cache.getHitCount() + 1);
cache.setLastTime(System.currentTimeMillis());
return cache.getValue();
}
}
4、最后是调用缓存的测试代码:
public class MyCacheTest {
public static void main(String[] args) {
CacheUtils cache = new CacheUtils();
// 存入缓存
cache.put("key", "老王", 10);
// 查询缓存
String val = (String) cache.get("key");
System.out.println(val);
// 查询不存在的缓存
String noval = (String) cache.get("noval");
System.out.println(noval);
}
}