浅谈后台应用的本地缓存

当缓存数据不需分布式共享, 且数据规模不大时, 我们就可以考虑使用应用的本地缓存.

本地缓存的设计重点:

1, 过期删除策略

2, 缓存淘汰策略

过期删除策略

对于设置了过期时间的缓存,删除策略一般分为: 定期删除、惰性删除.

定期删除:单独的线程对数据进行过期检查

惰性删除:当数据被查询时再判断是否过期

缓存淘汰策略

当缓存空间不足时, 需要开启淘汰机制, 常见的淘汰策略有: FIFO、LRU、LFU

FIFO(First In First out): 先进先出

当资源不足时, 干掉那些先出生的老人, 简单粗暴, 但是可能造成经常使用的缓存被无辜淘汰. 

LRU(Least recently used): 最近最少使用

LRU机制要求put缓存时,将数据放在链表的头部, get缓存时将数据移到链表的头部, 保证了最近使用的数据都在链表的头部区域, 最近最少使用的数据都在链表的尾部区域, 这样需要淘汰缓存时, 直接移除链表的尾部数据即可.

LFU(Least frequently used): 最少频率使用

LFU和LRU虽然都是基于“最少”使用,但“率”似乎更加准确, 就像现实中,我们经常用“增长率”来衡量增长指标一样. 

上面3种淘汰策略, 最常使用的是LRU, 可以满足绝大多数场景, 实现起来也比较简单. 我们熟知的谷歌Guava Cache就采用了LRU, 但总有人精益求精, 提出一些新的策略, 比如Caffeine的W-TinyLFU. //Spring5已经弃用Guava Cache而选择了Caffeine.

如果一个Java小应用, 不需要考虑“缓存淘汰”,只需要考虑“缓存过期”, 那我们就可以自定义一个简单的非工业级的本地缓存, 如下:  


import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 简单本地缓存,适用于小规模的静态数据。
 * 失效策略:"惰性删除",即每次查询时进行失效判断
 * 淘汰策略:无
 * @Author:tt
 * @Description:
 * @CreateTime:2018/11/11
 */
public class SimpleLocalCache {

    //ConcurrentHashMap并发读写
    private static ConcurrentHashMap<String, CacheData> cacheArea
            = new ConcurrentHashMap<>();

    //取缓存
    public static Object get(String key) {
        CacheData cacheData = cacheArea.get(key);
        if (cacheData == null) {
            return null;
        }
        if (isDead(cacheData)) {
            //惰性删除
            remove(key);
            return null;
        }
        return cacheData.getValue();
    }

    //放缓存
    public static boolean put(String key, Object value, long maxAge) {
        CacheData data = new CacheData();
        data.setCreateTime(new Date().getTime());
        data.setMaxAge(maxAge);
        data.setKey(key);
        data.setValue(value);
        cacheArea.put(key, data);
        return false;
    }

    //是否过期
    private static boolean isDead(CacheData data) {
        if (data == null) {
            return true;
        }
        if (data.getMaxAge() == 0) {
            return false;
        }
        long createTime = data.getCreateTime();
        long deadTime = createTime + data.getMaxAge();
        long nowTime = new Date().getTime();
        if (nowTime > deadTime) {
            return true;
        }
        return false;
    }

    //移除
    public static boolean remove(String key) {
        cacheArea.remove(key);
        return true;
    }

    //缓存数据封装
    static class CacheData {

        //创建时间:单位毫秒
        private long createTime;
        //缓存时常:单位毫秒, 0-标示永不失效
        private long maxAge;
        //数据key
        private String key;
        //数据value
        private Object value;

        //get、set方法略...
    }

    //测试
    public static void main(String[] args) throws InterruptedException {
        SimpleLocalCache.put("key1", "v1", 1000);
        SimpleLocalCache.put("key2", "v2", 5000);
        SimpleLocalCache.put("key3", "v3", 0);
        Thread.sleep(3000);
        System.out.println(SimpleLocalCache.get("key1"));//null
        System.out.println(SimpleLocalCache.get("key2"));//v2
        System.out.println(SimpleLocalCache.get("key3"));//v3
    }
}

 

 

转载于:https://my.oschina.net/wangxu3655/blog/2874548

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值