实现有过期功能的缓存

本地缓存(key会过期)

实现方案1: ConcurrentHashMap+key过期时间戳

1.1 查询缓存时,如果当前时间大于key的过期时间,则不返回,并且对该key进行删除
1.2 定时任务随机删除key,策略为随机从有过期时间的key中,抽样进行删除。

总结:性能最好,但是会占用比较多的内存空间

改进方案1

增加LRU算法,淘汰掉不常用的key值

改进方案2

使用延迟队列,对key定时删除

延迟队列实现

存储key的类

/**
 * @author Miguel.hou
 * @version v1.0
 * @date 2020-05-26
 */
@Data
@AllArgsConstructor
public class CacheItem implements Delayed {

    private String key;

    private String value;

    private Long expireSec;

    private Long currentTime;

    public CacheItem(String key, String value, Long expireSec) {
        this.key = key;
        this.value = value;
        this.expireSec = expireSec;
        this.currentTime = System.currentTimeMillis();
    }

    @Override
    public long getDelay(TimeUnit unit) {
        // 还剩多少时间过期
        return expireSec - TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - currentTime);
    }

    @Override
    public int compareTo(Delayed o) {
        return Long.compare(getDelay(TimeUnit.SECONDS), o.getDelay(TimeUnit.SECONDS));
    }
}

MyCahce.java

/**
 * @author Miguel.hou
 * @version v1.0
 * @date 2020-05-26
 */
public class MyCache implements Runnable {

    private boolean stop = false;

    private Map<String, CacheItem> cacheMap = new ConcurrentHashMap<>();
    private DelayQueue<CacheItem> expireDelayQueue = new DelayQueue<CacheItem>();

    public MyCache() {
        new Thread(this).start();
    }

    public synchronized void set(String key, String value, Long expireSec) {
        CacheItem cacheItem = cacheMap.get(key);
        if (cacheItem != null) {
            cacheMap.remove(key);
            expireDelayQueue.remove(cacheItem);
        }

        CacheItem newCacheItem = new CacheItem(key, value, expireSec);
        expireDelayQueue.add(newCacheItem);
    }

    @SneakyThrows
    @Override
    public void run() {
        while (!stop) {
            CacheItem cacheItem = expireDelayQueue.take();
            cacheMap.remove(cacheItem.getKey());
            System.out.println("============ remove cache:" + cacheItem.getKey());
        }
    }

    public void shutDown() {
        stop = true;
    }

    public static void main(String[] args) {
        MyCache myCache = new MyCache();
        myCache.set("miguel1", "123", 5L);
        myCache.set("miguel2", "123", 10L);
        myCache.set("miguel3", "123", 15L);

        try {
            Thread.sleep(30000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}