不使用淘汰策略的map的缓存实现方式
- 工具类
package cn.lazyfennec.mapcache;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @Author: Neco
* @Description: 基于map的缓存工具类
* @Date: create in 2022/6/8 21:55
*/
public class CacheProvider {
// 存放缓存的集合
private final static Map<String, CacheData> caches = new ConcurrentHashMap<>();
// 定时器线程池,用于清除过期缓存
private final static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(5);
// 1. 获取
public synchronized <T> T get(String key) {
CacheData cacheData = caches.get(key);
return cacheData == null ? null : (T) cacheData.data;
}
// 2. 插入
// 插入数据,不设置过期时间
public synchronized <T> void put(String key, T data) {
put(key, data, 0L); // 0L表示不设置过期时间, 小于等于0都表示不设置过期时间
}
// 插入数据,设置过期时间
public synchronized <T> void put(String key, T data, Long expire) {
if(expire > 0) {
executor.schedule(new Runnable() {
@Override
public void run() {
synchronized (this) {
caches.remove(key);
}
}
}, expire, TimeUnit.MILLISECONDS); // 设置指定的时间后执行删除
caches.put(key, new CacheData(data, expire));
} else {
caches.put(key, new CacheData(data, 0L));
}
}
// 3. 删除
public synchronized <T> T remove(String key) {
CacheData cacheData = caches.remove(key);
return cacheData == null ? null : (T) cacheData.data;
}
// 4. 总数
public synchronized Integer size() {
return caches.size();
}
public class CacheData {
// 数据
private Object data;
// 失效时间
private Long expire;
public CacheData(Object data, Long expire) {
this.data = data;
this.expire = expire;
}
}
}
- 测试类
package cn.lazyfennec.mapcache;
import org.junit.Test;
/**
* @Author: Neco
* @Description: 缓存测试类
* @Date: create in 2022/6/8 22:22
*/
public class CacheTest {
@Test
public void test() throws InterruptedException {
CacheProvider cache = new CacheProvider();
String key = "id";
// 不设置过期时间
System.out.println("*********** 不设置过期时间 ***********");
cache.put(key, 123);
System.out.println("key:" + key + ", value:" + cache.get(key));
System.out.println("key:" + key + ", value:" + cache.remove(key));
System.out.println("key:" + key + ", value:" + cache.get(key));
// 设置过期时间
System.out.println("*********** 设置过期时间 ***********");
cache.put(key, 123456, 1000L);
System.out.println("key:" + key + ", value:" + cache.get(key));
Thread.sleep(2000);
System.out.println("key:" + key + ", value:" + cache.get(key));
}
}
- 运行结果
*********** 不设置过期时间 ***********
key:id, value:123
key:id, value:123
key:id, value:null
*********** 设置过期时间 ***********
key:id, value:123456
key:id, value:null
使用FIFO淘汰策略的map的缓存实现方式
- 工具类
package cn.lazyfennec.mapcache;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @Author: Neco
* @Description: 基于map的缓存工具类, 使用FIFO缓存策略
* @Date: create in 2022/6/8 21:55
*/
public class FIFOCacheProvider {
// 存放缓存的集合
private Map<String, CacheData> caches = null;
// 定时器线程池,用于清除过期缓存
private final static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(5);
// FIFO
private static int MAX_CACHE_SIZE = 0; // 最大的容量
private final float LOAD_FACTORY = 0.75f; // 填充因子
public FIFOCacheProvider(int maxCacheSize) {
MAX_CACHE_SIZE = maxCacheSize;
// 根据缓存大小 和 填充因子计算cache的容量
int capacity = (int) (Math.ceil(MAX_CACHE_SIZE / LOAD_FACTORY) + 1);
caches = new LinkedHashMap<String, CacheData>(capacity, LOAD_FACTORY, false) {
// 是否刪除最旧数据的判定方法
@Override
protected boolean removeEldestEntry(Map.Entry<String, CacheData> eldest) {
return size() > MAX_CACHE_SIZE;
}
};
}
// 1. 获取
public synchronized <T> T get(String key) {
CacheData cacheData = caches.get(key);
return cacheData == null ? null : (T) cacheData.data;
}
// 2. 插入
// 插入数据,不设置过期时间
public synchronized <T> void put(String key, T data) {
put(key, data, 0L); // 0L表示不设置过期时间, 小于等于0都表示不设置过期时间
}
// 插入数据,设置过期时间
public synchronized <T> void put(String key, T data, Long expire) {
if (expire > 0) {
executor.schedule(new Runnable() {
@Override
public void run() {
synchronized (this) {
caches.remove(key);
}
}
}, expire, TimeUnit.MILLISECONDS); // 设置指定的时间后执行删除
caches.put(key, new CacheData(data, expire));
} else {
caches.put(key, new CacheData(data, 0L));
}
}
// 3. 删除
public synchronized <T> T remove(String key) {
CacheData cacheData = caches.remove(key);
return cacheData == null ? null : (T) cacheData.data;
}
// 4. 总数
public synchronized Integer size() {
return caches.size();
}
public class CacheData {
// 数据
private Object data;
// 失效时间
private Long expire;
public CacheData(Object data, Long expire) {
this.data = data;
this.expire = expire;
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, CacheData> entry: caches.entrySet()) {
sb.append(entry.getKey()).append("=").append(entry.getValue().data).append("\n");
}
return sb.toString();
}
}
- 测试类
package cn.lazyfennec.mapcache;
import org.junit.Test;
import java.util.UUID;
/**
* @Author: Neco
* @Description: 缓存测试类, FIFO
* @Date: create in 2022/6/8 22:22
*/
public class FIFOCacheTest {
@Test
public void test() {
FIFOCacheProvider cache = new FIFOCacheProvider(10);
for (int i = 0; i < 15; i++) {
cache.put("id" + i, UUID.randomUUID());
}
System.out.println("缓存的大小:" + cache.size());
System.out.println("缓存数据:\n" + cache.toString());
}
}
- 运行结果
缓存的大小:10
缓存数据:
id5=161f7873-d053-495f-a6ea-c79642f38ed3
id6=f03b0056-ccd2-4b70-9b2a-ab61056418dc
id7=a1164a62-87fd-40e2-a49a-33339f8c5cf1
id8=c0d2113a-1c0f-4003-a0c7-791114f5d9f9
id9=cdeddb2c-290b-49dc-b6c9-545cc9e66754
id10=be45b62d-ed81-4401-988a-e75cd53689ed
id11=716e1262-e44c-4e4c-a334-d6e5db8bad48
id12=0f2ae9b5-1c07-47e0-8a30-16ea3d24ae22
id13=188db819-d23e-4a5c-a071-65269369170c
id14=1ceb604c-8eab-489f-a0a1-0181a5f5831c
本文总结
- 实现并发读写?基于ConcrrentHashMap
- 实现缓存的定时、定期清除? 基于定时器
- 实现缓存的FIFO淘汰? 基于队列
如果觉得有收获就点个赞吧,更多知识,请点击关注查看我的主页信息哦~
网友评论