cache.put(“password”, “123456”);

// 从本地缓存中取出数据

System.out.println(cache.getIfPresent(“username”));

System.out.println(cache.getIfPresent(“password”));

System.out.println(cache.get(“blog”, key -> {

// 本地缓存没有的话,从数据库或者Redis中获取

return getValue(key);

}));

当然,使用本地缓存时,我们也可以使用异步加载机制:

AsyncLoadingCache<String, String> cache = Caffeine.newBuilder()

// 数量上限

.maximumSize(2)

// 失效时间

.expireAfterWrite(5, TimeUnit.MINUTES)

.refreshAfterWrite(1, TimeUnit.MINUTES)

// 异步加载机制

.buildAsync(new CacheLoader<String, String>() {

@Nullable

@Override

public String load(@NonNull String key) throws Exception {

return getValue(key);

}

});

System.out.println(cache.get(“username”).get());

System.out.println(cache.get(“password”).get(10, TimeUnit.MINUTES));

System.out.println(cache.get(“username”).get(10, TimeUnit.MINUTES));

System.out.println(cache.get(“blog”).get());

接下来,我们对一些重要特性进行更加深入的分析。

过期机制

本地缓存的过期机制是非常重要的,因为本地缓存中的数据并不像业务数据那样需要保证不丢失。本地缓存的数据一般都会要求保证命中率的前提下,尽可能的占用更少的内存,并可在极端情况下,可以被GC掉。

Caffeine的过期机制都是在构造Cache的时候申明,主要有如下几种:

  1. expireAfterWrite:表示自从最后一次写入后多久就会过期;

  2. expireAfterAccess:表示自从最后一次访问(写入或者读取)后多久就会过期;

  3. expireAfter:自定义过期策略;

刷新机制

在构造Cache时通过refreshAfterWrite方法指定刷新周期,例如refreshAfterWrite(10, TimeUnit.SECONDS)表示10秒钟刷新一次:

.build(new CacheLoader<String, String>() {

@Override

public String load(String k) {

// 这里我们就可以从数据库或者其他地方查询最新的数据

return getValue(k);

}

});

需要注意的是,Caffeine的刷新机制是**「被动」的。举个例子,假如我们申明了10秒刷新一次。我们在时间T访问并获取到值v1,在T+5秒的时候,数据库中这个值已经更新为v2。但是在T+12秒,即已经过了10秒我们通过Caffeine从本地缓存中获取到的「还是v1」**,并不是v2。在这个获取过程中,Caffeine发现时间已经过了10秒,然后会将v2加载到本地缓存中,下一次获取时才能拿到v2。即它的实现原理是在get方法中,调用afterRead的时候,调用refreshIfNeeded方法判断是否需要刷新数据。这就意味着,如果不读取本地缓存中的数据的话,无论刷新时间间隔是多少,本地缓存中的数据永远是旧的数据!

剔除机制

在构造Cache时可以通过removalListener方法申明剔除监听器,从而可以跟踪本地缓存中被剔除的数据历史信息。根据RemovalCause.java枚举值可知,剔除策略有如下5种:

  • 「EXPLICIT」:调用方法(例如:cache.invalidate(key)、cache.invalidateAll)显示剔除数据;

  • 「REPLACED」:不是真正被剔除,而是用户调用一些方法(例如:put(),putAll()等)改了之前的值;

  • 「COLLECTED」:表示缓存中的Key或者Value被垃圾回收掉了;

  • 「EXPIRED」: expireAfterWrite/expireAfterAccess约定时间内没有任何访问导致被剔除;

  • 「SIZE」:超过maximumSize限制的元素个数被剔除的原因;

GuavaCache和Caffeine差异

========================================================================================

  1. 剔除算法方面,GuavaCache采用的是**「LRU」算法,而Caffeine采用的是「Window TinyLFU」**算法,这是两者之间最大,也是根本的区别。

  2. 立即失效方面,Guava会把立即失效 (例如:expireAfterAccess(0) and expireAfterWrite(0)) 转成设置最大Size为0。这就会导致剔除提醒的原因是SIZE而不是EXPIRED。Caffiene能正确识别这种剔除原因。

  3. 取代提醒方面,Guava只要数据被替换,不管什么原因,都会触发剔除监听器。而Caffiene在取代值和先前值的引用完全一样时不会触发监听器。

  4. 异步化方方面,Caffiene的很多工作都是交给线程池去做的(默认:ForkJoinPool.commonPool()),例如:剔除监听器,刷新机制,维护工作等。

内存占用对比

=========================================================================

Caffeine可以根据使用情况延迟初始化,或者动态调整它内部数据结构。这样能减少对内存的占用。如下图所示,使用了gradle memoryOverhead对内存占用进行了压测。结果可能会受到JVM的指针压缩、对象Padding等影响:

干掉GuavaCache:Caffeine才是本地缓存的王

LRU P.K. W-TinyLFU

=====================================================================================

缓存的驱逐策略是为了预测哪些数据在短期内最可能被再次用到,从而提升缓存的命中率。由于简洁的实现、高效的运行时表现以及在常规的使用场景下有不错的命中率,LRU(Least Recently Used)策略或许是最流行的驱逐策略,,它在保持算法简单的前提下,效果还不错。但LRU对未来的预测有明显的局限性,它会认为**「最后到来的数据是最可能被再次访问」**的,从而给予它最高的优先级。

现代缓存扩展了对历史数据的使用,结合就近程度(recency)和访问频次(frequency)来更好的预测数据。其中一种保留历史信息的方式是使用**「popularity sketch」(一种压缩、概率性的数据结构)来从一大堆访问事件中定位频繁的访问者。可以参考「CountMin Sketch」**算法,它由计数矩阵和多个哈希方法实现。发生一次读取时,矩阵中每行对应的计数器增加计数,估算频率时,取数据对应是所有行中计数的最小值。这个方法让我们从空间、效率、以及适配矩阵的长宽引起的哈希碰撞的错误率上做权衡:

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
img

最后

我还为大家准备了一套体系化的架构师学习资料包以及BAT面试资料,供大家参考及学习

已经将知识体系整理好(源码,笔记,PPT,学习视频)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

最后

我还为大家准备了一套体系化的架构师学习资料包以及BAT面试资料,供大家参考及学习

已经将知识体系整理好(源码,笔记,PPT,学习视频)

[外链图片转存中…(img-Xbi97wsD-1711108208762)]

[外链图片转存中…(img-bIJXtnlO-1711108208762)]

[外链图片转存中…(img-HYyodq0P-1711108208763)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

Logo

欢迎加入西安开发者社区!我们致力于为西安地区的开发者提供学习、合作和成长的机会。参与我们的活动,与专家分享最新技术趋势,解决挑战,探索创新。加入我们,共同打造技术社区!

更多推荐