guava|guava 缓存过期策略
2019独角兽企业重金招聘Python工程师标准>>>
文章图片
google的guava可谓鼎鼎有名,最近在研究缓存,也就看看它是怎么处理缓存过期问题的;首先它并没有通过在后台起一个线程,不停去轮询。不这么做主要是为了效率吧,也就是所谓的惰性移除,在get时判断是否过期。那如果一直不访问,可能存在内存泄漏问题。
示例代码:
Cache
1,CacheBuilder默认的缓存实现为LocalCache,所以这里我们主要去研究LocalCache的getIfPresent 即可
2,通过观察,我们可以猜出LocalCache 是用类似于ConcurrentHashMap 的数据结构来保存数据的
3,这里我们主要看其Segment 的get 方法,然后进入getLiveEntry 方法,看名字感觉跟存活有关,点进去
ReferenceEntry getLiveEntry(Object key, int hash, long now) {
//获取值
ReferenceEntry e = getEntry(key, hash);
if (e == null) {//如果为空,返回空
return null;
} else if (map.isExpired(e, now)) {//判断是否过期
tryExpireEntries(now);
return null;
}
return e;
}boolean isExpired(ReferenceEntry entry, long now) {
checkNotNull(entry);
if (expiresAfterAccess() && (now - entry.getAccessTime() >= expireAfterAccessNanos)) {
return true;
}
if (expiresAfterWrite() && (now - entry.getWriteTime() >= expireAfterWriteNanos)) {
return true;
}
return false;
}
maximumSize作用原理,猜想:应该是在put缓存时,检查是否达到了最大值,如果达到则用LRU算法移除一个cache
1,观察LocalCache#put
V put(K key, int hash, V value, boolean onlyIfAbsent) {
lock();
try {
...
evictEntries(newEntry);
//这行代码,看名字感觉就是它,点进去看
return null;
} finally {
unlock();
postWriteCleanup();
}
}void evictEntries(ReferenceEntry newest) {
....while (totalWeight > maxSegmentWeight) {
ReferenceEntry e = getNextEvictable();
if (!removeEntry(e, e.getHash(), RemovalCause.SIZE)) {
throw new AssertionError();
}
}
}
这里我们不妨看看它的LRU算法是如何实现的
ReferenceEntry getNextEvictable() {
for (ReferenceEntry e : accessQueue) {
int weight = e.getValueReference().getWeight();
if (weight > 0) {
return e;
}
}
throw new AssertionError();
}
发现它是用队列实现的,也就是在插入新缓存是有排序。
总结:
我们时常会有本地缓存的需求,这时不妨看看google是怎么做的,可以给我们一个参考
【guava|guava 缓存过期策略】转载于:https://my.oschina.net/u/3574106/blog/3016413
推荐阅读
- Guava|Guava RateLimiter与限流算法
- 不废话,代码实践带你掌握|不废话,代码实践带你掌握 强缓存、协商缓存!
- 15、IDEA学习系列之其他设置(生成javadoc、缓存和索引的清理等)
- springboot使用redis缓存
- 缓存有关的配置和属性
- 那支过期的口红,我始终舍不得扔
- crontab无法查看,原来是密码过期了
- 过期不候
- LRU|LRU java 实现
- 框架|Mybatis的一级缓存和二级缓存