“携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情
背景
为什么要使用本地缓存
- 本地缓存基于本地环境的内存,访问速度非常快,对于一些变更频率低、实时性要求低的数据,可以放在本地缓存中,提升访问速度
- 使用本地缓存能够减少和Redis类的远程缓存间的数据交互,减少网络I/O开销,降低这一过程中在网络通信上的耗时
基于Guava Cache实现本地缓存
LoadingCache是GuavaCache构建缓存实体的方法,是一个支持多线程并发读写、高性能、通用的本地缓存。它是线程安全的!
private LoadingCache<String,Map<String,String>> cache = CacheBuilder.newBuilder()
//设置缓存容器的初始容量为2
.initialCapacity(2)
//缓冲池大小
.maximumSize(2)
//设置时间 对象没有写访问则对象从内存中删除
.expireAfterWrite(1, TimUnit.HOURS)
//build方法中可以指定CacheLoader,在缓存不存在时通过CacheLoader的实现自动加在缓存
.build(new CacheLoader<String, Map<String,String>>(){
@Override
public Map<String, String> load(String key) throws Exception{
//具体的实现逻辑
......
}
);
CacheBuilder方法
- initialCapacity():设置缓存容器的初始容量
- maximumSize():配置缓存数量上限,超过设定值就会根据LRU最近最少使用算法来移除对象
- expireAfterWrite():设置时间,对象没有被写访问则对象从内存中删除
- expireAfterAccess():设置时间,对象没有被读/写访问则对象从内存中删除 --使用较少
- refreshAfterWrite():定时刷新,可以为缓存增加自动定时刷新功能
expireAfterWrite为了避免缓存雪崩,guava会限制只有一个加载操作时进行加锁,其他请求必须阻塞等待这个加载操作完成。而且,在加载完成之后,其他请求的线程会逐一获得锁,去判断是否已被加载完成,每个线程必须轮流的走一个获得锁,获得值,释放锁”的过程,这样性能会有一些损耗。
refreshAfterWrite当缓存项上一次更新操作之后的多久会被刷新。在refresh的过程中,guava会限制只有一个加载操作时进行加锁,而其他查询先返回旧值,这样能有效减少等待和锁争用,所以refreshAfterWrite会比expireAfterWrite性能好。
V get(K k):内部调用getOrLoad(K key)方法,缓存中有对应的值则返回,没有则使用CacheLoader load方法