自命为缓存之王的Caffeine(2)
您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来~
缓存除了过期策略,其实还有刷新和填充策略。刷新策略就是当数值变化时怎么处理,而所谓填充策略,就是将数据保存到缓存的方式。
Caffeine提供了三种刷新方法:
1、基于类Caffeine的refreshAfterWrite(time, duration)方法;
2、基于接口LoadingCache的refresh(key)方法;
3、基于CacheLoader的reload(K, V)。
通过类的Caffeine.refreshAfterWrite()方法实现更新:
refreshAfterWrite()方法是一种「被动」更新,它必须设置CacheLoad,key过期后并不立即刷新value:
1、当过期后第一次调用get()方法时,得到的仍然是过期值;
2、当过期后第二次调用get()方法时,才会得到更新后的值。
这感觉有点bug。
第二种是通过接口的LoadingCache.refresh(Key)方法实现更新:
而refresh(Key)方法只要调用了,当再次读取时,就是最新的值(这一点和refreshAfterWrite()方法是有区别的)。
最后一种刷新策略有两类情况,一是Cache类覆盖CacheLoader.reload(K, V)方法,二是LoadingCache类覆盖CacheLoader.reload(K, V)方法:
可以比较使用Cache和LoadingCache,看看其中的细微差别。而使用不同的Cache涉及到Caffeine另一个方面:缓存填充。Caffeine提供了三种「填充」方法:
1、手动;
2、同步;
3、异步。
它们的区别在于:
1、手动方式可以显式地控制检索、更新和删除条目,控制起来比较方便,适用于大多数场景;
2、异步方式由于需要使用组合异步CompletableFuture,很明显是用于保存需要占用较大内存的对象,且这类保存操作比较费时;
3、同步方式介于手动和异步之间,适用于需要从外部加载数据源,或者需要保存全局变量的情况(其实get(key, k -> v)方法更适合);
4、从之前的操作来看,同步方式对refresh(Key)方法支持得很好,而且get()、get(key, k -> v)和getIfPresent()对结果也有影响;
5、这有点类似于排列组合:不同的填充策略 + 不同的get()方法 + 不同的刷新策略,就会产生不同的结果,这需要开发者对Caffeine有足够多的使用和了解,才能完全驾驭。
最后的一个问题是:Caffeine的get(key, k -> v)与getIfPresent()到底有啥不同?
通过阅读Caffeine源码了解到:
1、LoadingCache接口只有get(key)方法,继承于Cache;
2、Cache接口有get(key, k -> v)方法;
3、AsyncCache接口也有get(key, k -> v)方法。
不管是哪种填充方式,都有get(key, k -> v)方法。
get(key, k -> v)方法是以阻塞方式调用,在多个线程环境下,只会调用一次Function函数,这可以避免与其他线程的写入竞争,因此get(key, k -> v)优于getIfPresent()。
建议使用get(key, k -> v)方法,更安全,更通用。
感谢您的大驾光临!咨询技术、产品、运营和管理相关问题,请关注后留言。欢迎骚扰,不胜荣幸~