1、存储集合的选择
实现本地缓存,存储结构一定要是 (K/V)的数据结构,在程序中,也就是我们常用的 Map 容器。在Map 汇总HashMap、Hashtable、ConcurrentHashMap 这几种容器供我们选择,如果不考虑并发的情况就使用 HashMap(存在并发不安全),如果考虑到并发可以选择Hashtable、ConcurrentHashMap这两种容器,Hashtable效率不咋滴,所以优选ConcurrentHashMap,ConcurrentHashMap是基于AQS进行并发操作的
2、缓存过期处理
缓存时直接存储在内存中的,肯定是要清理的,本地缓存只能拿来做临时缓存,如果做长时间缓存或者不清理这样数据会原来越多,造成太多无用的数据占用内存资源,如果做长时间缓存可以使用第三方,用 Redis 等 NoSql 数据库来做、
Redis 是采用的定时删除 + 懒惰淘汰策略
定时删除策略:
定时删除策略是是每隔一段时间检查已过期的缓存,并且将之删除。这个策略是有点事能够确保过期的策略都会被删除,同时也存在缺点,过期的缓存不一定能够及时删除,这个跟我们设置的定时频率和选择的处理方式有很大的关系,如果使用定时线程扫描删除的话如果在缓存数据过多的情况下进行数据的扫描会给CPU带来压力,所以也可以使用 DelayQueue 来设置到期自动出列后调用 Remove 进行删除,具体的方式可以根据实际业务灵活进行选择
懒惰淘汰策略
懒惰淘汰策略是其在使用缓存时先判断是否过期,如果过期则将它删除,并且返回false。这个策略的有点只有在在缓存命中的时候才会判断是否过期,对CPU的影响较小,但有另一个缺点,当存入大量的缓存时,这些缓存没有被使用并且已经过期了都会成为无效缓存,这些垃圾数据会大量的占用宝贵的内存空间还会影响查找性能,最终导致服务器内存溢出
上面两个策略都有自己的优缺点,所以在我们实际使用过程中,可以将两种策略组合起来,结合效果还是很理想的
3、缓存淘汰策略
淘汰策略很过期缓存要区别开来,缓存淘汰是只当我们的缓存个数达到我们制定的缓存个数则进行缓存淘汰。毕竟我们的内存不是没有限制的,如果我们需要继续添加缓存的话,则就需要进行某种淘汰机制淘汰掉不需要的数据给新进来的缓存腾位置。
先进先出策略:
最先进入的数据在缓存空间不够用的情况下则优先清除掉,以腾出新的空间接收新的数据,改策略主要是比较缓存元素的创建时间。在一些数据时效性要求比较高的场景下,可考虑选择该类策略,保障最新数据是可用的
最少使用策略
无论解释过期,都会根据使用的次数进行判断使用次数据较少的元素进行删除,在保证高频数据有效性场景下,可选择这类策略
最近最少使用策略
无论是否过期都根据元素最后一次被使用的时间错,清除创建时间最长及使用次数最少的数据,
随机淘汰策略
无论是否过期,在使用空间到了一定的程度之后则调用方法随机选择元素进行删除,不建议使用此策略,万一你刚新建一个数据马上就给你删除了
不淘汰策略
在缓存达到指定值之后不淘汰任何缓存,而是不让新增缓存,知道有缓存数据被淘汰后才能继续添加缓存
代码实现:
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
public class Cache implements Delayed{
//消息过期存储容器
protected static Map<String,Cache> concurrentHashMap = new ConcurrentHashMap<String,Cache>();
// 键
private String key;
private Object value;
//延迟时间
private long delayTime ;
public Cache(String key, long delayTime) {
this.key = key;
this.delayTime = delayTime+System.currentTimeMillis();
}
public Cache() {
}
/**
* 添加缓存
*
* @param key
* @param value2
*/
public static void put(String key, Object value,long expire) {
// 当缓存存在时,更新缓存
if (concurrentHashMap.containsKey(key)){
Cache cache = concurrentHashMap.get(key);
put(cache,key,value, expire);
return;
}
Cache cache = new Cache();
put(cache,key,value, expire);
concurrentHashMap.put(key, cache);
}
public static Cache put(Cache cache,String key,Object value,long expire){
cache.setValue(value);
DelayMsgQueue.putDelayMsg(key, 30000);
return cache;
}
public static Cache get(String key) {
return concurrentHashMap.get(key);
}
public static Cache remove(String key) {
return concurrentHashMap.remove(key);
}
public long getDelayTime() {
return delayTime;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
public void setDelayTime(long delayTime) {
this.delayTime = delayTime;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
/*
* 这个方法返回到激活日期的剩余时间,时间单位由单位参数指定。
*/
public long getDelay(TimeUnit unit) {
return unit.convert(this.delayTime -System.currentTimeMillis(),unit);
}
/*
*Delayed接口继承了Comparable接口,按剩余时间排序,实际计算考虑精度为纳秒数
*/
public int compareTo(Delayed o) {
long d = (getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));
if (d==0){
return 0;
}else{
if (d<0){
return -1;
}else{
return 1;
}
}
}
}
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.DelayQueue;
/**
*类说明:将信息推入队列
*/
public class DelayMsgQueue extends Cache{
protected volatile static BlockingQueue<Cache> queueMsg = new DelayQueue<Cache>();
static {
new Thread(new Runnable() {
public void run() {
try {
while(true) {
System.out.println("进行监听删除");
String message = DelayMsgQueue.queueMsg.take().getKey();
concurrentHashMap.remove(message);
System.out.println(message);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
public static void putDelayMsg(String key,long time) {
try {
queueMsg.put(new Cache(key,time));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

