很多时候都需要使用到缓存工具-(不过目前有很多专业的缓存工具,写这个东西仅仅是为了梳理缓存的逻辑)
首先定义一个存储工具使用的 ConcurrentHashMap(支持并发)
private volatile Map data = new ConcurrentHashMap<>(16);
缓存应该具备到期自动删除的功能,所以需要对要存储的对象进行包装
@Data
class CacheObject {
/**
* 需要存储的值
*/
private Object value;
/**
* dateline(存储的时候计算)
*/
private long expire;
public CacheObject() {
}
public boolean isExpire() {
return System.currentTimeMillis() > expire;
}
public CacheObject(Object value, long expire) {
this.value = value;
this.expire = expire;
}
}
增加添加和获取的方法
在添加数据是要考虑过期时间
/**
* @param key 要存储的key
* @param value 要存储的值
* @param expire 过期时间
* @return
*/
public boolean add(String key, Object value, long expire) {
CacheObject cacheObject = new CacheObject(value, expire + System.currentTimeMillis());
data.put(key, cacheObject);
return true;
}
/**
* 根据key获取值
*
* @param key 指定的key
* @return
*/
public Object get(String key) {
CacheObject cacheObject = data.get(key);
if (Objects.isNull(cacheObject)) {
return null;
}
return cacheObject.getValue();
}
此时还需要一个定时任务要不停的去监听数据是否过期
/**
* 定时任务删除过期的数据
*/
private void init() {
ScheduledThreadPoolExecutor scheduled = new ScheduledThreadPoolExecutor(5);
scheduled.scheduleWithFixedDelay(() -> {
data.entrySet().removeIf(entry -> Objects.nonNull(entry) && entry.getValue().isExpire());
}, 100, 100, TimeUnit.MILLISECONDS);
}
测试代码
public static void main(String[] args) throws InterruptedException {
HashMapCache cache = new HashMapCache();
cache.add("AAA", "AAA", 2000);
cache.add("BBB", "BBB", 2000);
cache.add("CCC", "CCC", 2000);
cache.add("DDD", "DDD", 2000);
System.out.println(cache.get("BBB"));
Thread.sleep(5001);
System.out.println(cache.get("BBB"));
}
考虑垃圾回收机制问题,所以升级为软引用,在内存爆掉前释放资源,全部代码如下
package com.milla.study.netbase.expert.memory;
import lombok.Data;
import java.lang.ref.SoftReference;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @author milla
*/
public class HashMapCacheSoftReference {
private volatile Map> data = new ConcurrentHashMap<>(16);
public static void main(String[] args) throws InterruptedException {
HashMapCacheSoftReference cache = new HashMapCacheSoftReference();
System.out.println(cache.get("BBB"));
Thread.sleep(5001);
System.out.println(cache.get("BBB"));
}
public HashMapCacheSoftReference() {
init();
}
private void init() {
ScheduledThreadPoolExecutor scheduled = new ScheduledThreadPoolExecutor(5);
scheduled.scheduleWithFixedDelay(() -> {
data.entrySet().removeIf(o -> Optional.ofNullable(o.getValue()).map(SoftReference::get).map(CacheObject::isExpire).orElse(false));
}, 100, 100, TimeUnit.MILLISECONDS);
}
public boolean add(String key, Object value, long expire) {
if (key == null) {
return false;
}
if (Objects.isNull(value)) {
return false;
}
CacheObject cacheObject = new CacheObject(value, expire + System.currentTimeMillis());
data.put(key, new SoftReference<>(cacheObject));
return true;
}
public Object get(String key) {
SoftReference cacheObjectSoftReference = data.get(key);
if (Objects.isNull(cacheObjectSoftReference)) {
return null;
}
CacheObject cacheObject = cacheObjectSoftReference.get();
if (Objects.isNull(cacheObject)) {
return null;
}
return cacheObject.getValue();
}
@Data
class CacheObject {
/**
* 需要存储的值
*/
private Object value;
/**
* dateline(存储的时候计算)
*/
private long expire;
public CacheObject() {
}
public boolean isExpire() {
return System.currentTimeMillis() > expire;
}
public CacheObject(Object value, long expire) {
this.value = value;
this.expire = expire;
}
}
}
ps: 有很多优秀的缓存工具,考虑的更加细致,所以只需要知道大体实现思路即可,没必要自己造轮子
以下是guava缓存的部分
maven依赖
com.google.guava
guava
28.2-jre
测试代码
public static void main(String[] args) throws ExecutionException {
CacheBuilder