平凡也就两个字: 懒和惰;
成功也就两个字: 苦和勤;
优秀也就两个字: 你和我。
跟着我从0学习JAVA、spring全家桶和linux运维等知识,带你从懵懂少年走向人生巅峰,迎娶白富美!
关注微信公众号【 IT特靠谱 】,每天都会分享技术心得~
【java】本地(内存)缓存实战--LocalCache
数据缓存有多种方式,也有不同存储媒介。如redis、cookie、session、memcache等,这里却要说的是一种存储在内存中的对象缓存,这里称为:LocalCache。
闲话少说,重点都在代码里面!
1 缓存工具类
我把实现本地缓存的代码整理形成了一个java工具类:LocalCacheUtil.java。
1)调用save()方法,可以添加缓存,并指定过期时间。
2)调用load()方法可以从本地缓存中读取数据,如果缓存过期了,则返回null,业务层需要从数据库等持久化存储库中查询数据,并再次缓存起来。
3)也可以调用clearCache()方法手动删除指定key缓存。
4)定时任务会每隔5分钟定时清理一次已过期的缓存数据。
package com.hc.alltest.localCache;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.util.TypeUtils;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
/**
* 本地内存缓存工具类
*/
@Slf4j
public class LocalCacheUtil {
private LocalCacheUtil() {
}
// 定时任务执行器
private static ScheduledExecutorService refreshExecutor = new ScheduledThreadPoolExecutor(1, Executors.defaultThreadFactory());
// 当前缓存
private static volatile ConcurrentHashMap<String, CacheElement<Object>> cacheMap = new ConcurrentHashMap<>();
// 缓存对象
static class CacheElement<T extends Object> {
// 缓存值
private T value;
// 过期时间
private Long expire;
/**
* 有参数构造方法
*
* @param value 缓存的值
* @param timeout 过期时间。单位:ms
*/
public CacheElement(T value, Long timeout) {
this.value = value;
this.expire = System.currentTimeMillis() + timeout;
}
/**
* 判断缓存是否过期
*/
public boolean isOvertime() {
return expire < System.currentTimeMillis();
}
}
/**
* 读取本地缓存
*
* @param key 缓存key
* @param requireClass 缓存值对应class
*/
public static <T extends Object> T load(String key, Class<T> requireClass) {
CacheElement<Object> e = cacheMap.get(key);
//过期返回null
if (null == e || e.isOvertime()) {
return null;
}
return TypeUtils.cast(e.value, requireClass, ParserConfig.getGlobalInstance());
}
/**
* 保存至本地缓存
*
* @param key 缓存key
* @param value 缓存值
* @param timeout 过期时间。单位:ms
*/
public static <T extends Object> void save(String key, T value, Long timeout) {
cacheMap.put(key, new CacheElement<>(value, timeout));
}
/**
* 手动清除key对应的本地缓存
*/
public static void clearCache(String key) {
cacheMap.put(key, null);
}
/**
* 定时(每5分钟)清理一次缓存中过期的数据
*/
static {
refreshExecutor.scheduleAtFixedRate(() -> {
ConcurrentHashMap<String, CacheElement<Object>> newCache = new ConcurrentHashMap<>();
for (Map.Entry<String, CacheElement<Object>> e : cacheMap.entrySet()) {
// 丢弃已经过期的数据
if (e.getValue().isOvertime()) {
continue;
}
newCache.put(e.getKey(), e.getValue());
}
cacheMap = newCache;
}, 0, 5 * 60, TimeUnit.SECONDS);
}
}
2 测试本地缓存
往本地缓存中缓存一个键为:name,值为:张三 的数据。然后循环从本地缓存中读取name键对应的缓存数据。
package com.hc.alltest.localCache;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
/**
* 测试本地缓存
*/
@Slf4j
public class Main {
public static void main(String[] args) throws Exception {
//缓存数据
LocalCacheUtil.save("name", "张三", 600L);
while (true) {
//从缓存读取数据
String cacheValue = LocalCacheUtil.load("name", String.class);
log.info("cacheValue:" + cacheValue);
if(StringUtils.isEmpty(cacheValue)){
break;
}
Thread.sleep(100L);
}
}
}
关注微信公众号,免费获取java及其相关视频教程~