你在guava cache上设置的更新参数是否有用?

Guava Cache 原理分析与最佳实践 阿里伤透我心,疯狂复习刷题,终于喜提offer 哈哈~好啦,不闲扯了1、JAVA面试核心知识整理(PDF):包含JVMJAVA集合JAVA多线程并发,JAVA基础,Spring原理微服务,Netty与RPC,网络,日志,ZookeeperKafkaRabbitMQ,Hbase,MongoDB设计模式负载均衡数据库一致性哈希JAVA算法数据结构,加密算法,分布式缓存,Hadoop,Spark,Storm,YARN,机器学习,云计算共30个章节。2、Redis学习笔记及学习思维脑图。 阅读详情

guava cache是一种支持自动回收、刷新的concurrentHashMap。显然防止内存溢出是其核心功能,包括主动刷新refresh、过期失效expire、java的软/虚引用以及设置最大的size和weight。在实际开发中,个人对于expire和refresh使用较多,expire又分为expireAfterAccess、expireAfterWrite,现对比下三者的区别:

expireAfterAccessexpireAfterWriterefreshAfterWrite
功能读写后回收写后回收定时刷新
更新方法loadload首次load,其他reload
触发线程读取线程读取线程读取线程+异步线程(如果重写reload使用额外线程,默认没异步)
并行非更新线程同步通过ReentrantLock加锁,其他线程等待加载完成通过ReentrantLock加锁 ,其他线程等待加载完成不加锁,其他线程返回旧值
高并发读取问题可能造成同一key永不过期--
高并发更新问题频繁上锁解锁导致性能问题频繁上锁解锁导致性能问题-
低频读取问题--refresh并非异步线程定时刷新,而是由请求线程触发,在低频访问下,某个key的value可能是较早之前读取留下的,距离现在已久,会读取到较老的值

综上所看,expire和refresh都各有优缺点,refresh在低频访问可能获取到一个较老的值,而expire在高频率的收回时候因为每个线程都会加锁解锁而有性能问题。实际开发中,将两者综合使用,通过各自的优点屏蔽掉对方的缺点。比如设定refresh为1分钟一次,expireAfterWrite为2分钟一次,那么在访问高峰下,大部分会通过refresh的异步线程触发更新,避免了加锁。而当程序处于访问低谷时候,通过expire设置最大有效期为2分钟回收,后进来的线程发现已被回收再通过加锁的方式读取新值,因为量小,加锁的性能问题也可以很好的规避。

源码

可能有些同学会问,如果refresh和expireAfterWrite的更新频率都设置成一样的话,比如都是1分钟更新,那究竟是通过哪一种方式来更新呢?

答案是通过expire来更新。通过下面简化版的源码分析原因。

//与concurrentHashMap一样,获取值时候传入key与计算key的hash
V get(K key,int hash )  {
          ReferenceEntry<K, V> e = getEntry(key, hash);
          if (e != null) {
            //获取当前时间
            long now = map.ticker.read();
            //获取存活的值,即判断是否有过期的值
            V value = getLiveValue(e, now);
            if (value != null) {
              //不存在过期,判断是否符合refresh条件触发执行refresh
              return scheduleRefresh(e, key, hash, value, now, loader);
            }
            ValueReference<K, V> valueReference = e.getValueReference();
            //已回收的或者新的值时候,val都是null,此时统一key其他线程访问需要等待
            if (valueReference.isLoading()) {
              return waitForLoadingValue(e, key, valueReference);
            }
          }
        }

        // at this point e is either null or expired;
        // 不是空就是过期才会调到这个方法,即首次或者过期会加锁读取
        return lockedGetOrLoad(key, hash, loader);
    }

可以看出,guava是先判断是否有存活live的对象,如果有存活,才会进行refresh操作,如果没有存活,可能的情况是expire造成的回收或者从未有过值,这时候进行上锁lock和load取新的值,竞争的其他线程则wait等待结果。所以refresh设置的更新频率大于expire,即refresh的更新更频繁,否则refresh的设置相当于无效。

实验

为此我们做出下面的实验,通过expire调用load,refresh非首次调用reload的特性,验证上面的结论。

 @Test
    public void testExpireAndRefresh() {
        ExecutorService executor = Executors.newFixedThreadPool(1);
        ListeningExecutorService listeningExecutorService = MoreExecutors.listeningDecorator(executor);

        AtomicInteger count = new AtomicInteger(0);
        LoadingCache<String, Integer> cache = CacheBuilder.newBuilder()
                .expireAfterWrite(1, TimeUnit.SECONDS)
                .refreshAfterWrite(2, TimeUnit.SECONDS)
                .build(new CacheLoader<String, Integer>() {
                    @Override
                    public Integer load(String key) throws Exception {
                        return count.getAndIncrement();
                    }

                    @Override
                    public ListenableFuture<Integer> reload(String key, Integer oldValue) throws Exception {
                        return listeningExecutorService.submit(()-> count.getAndIncrement()+10000);
                    }
                });
        IntStream.range(0, 10).forEach(i -> {
            System.out.println(cache.getUnchecked(""));
            ThreadUtil.safeSleep(1000);
        });
    }

执行结果如下,正如我们所料,调用都是load方法。

0
1
2
3
4
5
6
7
8
9

Process finished with exit code 0

同样,我们调用expire和refresh都设置成1,还是以上的结果。接着我们设置成refresh频率更高的情况

.expireAfterWrite(2, TimeUnit.SECONDS)
.refreshAfterWrite(1, TimeUnit.SECONDS)

结果也证明了原来的猜想

0
10001
10001
10002
10003
10004
10005
10006
10007
10008
Process finished with exit code 0

NOTE

除了提到的refresh和expire的更新频率问题,我们在实际开发中,最好将reload的方法异步处理,默认reload是直接调用load方法,且同步实现。因为在refresh reload后还有部分操作,异步可以并行化改块内容,加快refresh执行效率(也是官方推荐的方式)。我们可以通过CacheLoader.asyncReloading简化改部分的异步实现。

 ListeningExecutorService listeningExecutorService = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());

 LoadingCache<String, Integer> cache2 = CacheBuilder.newBuilder()
                .expireAfterWrite(2, TimeUnit.SECONDS)
                .refreshAfterWrite(1, TimeUnit.SECONDS)
                .build(CacheLoader.asyncReloading(new CacheLoader<String, Integer>() {
                    @Override
                    public Integer load(String key) throws Exception {
                        return count.getAndIncrement();
                    }

                }, executor));
Caffeine 与 Guava Cache Caffeine 与 Guava Cache 一、概要 1.1 背景 在项目开发中,为提升系统性能,减少 IO 开销,本地缓存是必不可少的。最常见的本地缓存是 Guava 和 Caffeine,Caffeine 是基于 Google Guava Cache 设计经验改进的结果,相较于 Guava 在性能和命中率上更具有效率。 1.2 应用场景 愿意消耗一些内存空间来提升速度 预料到某些键会被多次查询 缓存中存放的数据总量不会超出内存容量 二、Guava Cache 2.1 Guava Cache缓存回收 ( 阅读详情

相关推荐

SpringBoot 整合 Guava Cache 实现本地缓存

美团技术团队-缓存那些事是 Google 开发的 Guava 工具包中一套完善的JVM 本地缓存框架,底层实现的数据结构类似于,但是进行了更多的能力拓展,包括缓存过期时间设置、缓存容量设置、多种淘汰策略、缓存监控等。是一个支持高并发的线程安全的本地缓存。多线程情况下也可以安全的访问或者更新Cache。这些都是借鉴了支持最大容量限制支持两种过期删除策略(插入时间和读取时间)支持简单的统计功能基于 LRU 算法实现。

sco5282的博客 3590

Guava Cache自动加载异步刷新代码实现

public interface ILocalCache<K, V>{ /** * 从缓存中获取数据 * @param key * @return value */ public V get(K key); } /** * @Description: 用于初始化cache的参数及其缺省值 */ public abstrac...

meser88的博客 3878

本地缓存之Guava Cache

Guava cache是一个支持高并发的线程安全的本地缓存。多线程情况下也可以安全的访问或者更新Cache。这些都是借鉴了ConcurrentHashMap的结果。不过,guava cache 又有自己的特性当cache中不存在要查找的entry的时候,它会自动执行用户自定义的加载逻辑,加载成功后再将entry存入缓存并返回给用户未过期的entry,如果不存在或者已过期,则需要load。

PJ码匠人 1350

GuavaCache的refreshAfterWrite

expireAfterAccess:一段时间内没有访问则过期,如果有多个线程同时查询,则阻塞所有线程,一个线程去获取数据。refreshAfterWrite:可以不重写reload。如果缓存过期,则一个线程去获取数据,其他线程返回老数据。expireAfterWrite:如果缓存过期,则阻塞所有线程,一个线程去获取数据。

tangxz的博客 9272

guava之guava cache

caffine的原文翻译 https://segmentfault.com/a/1190000008751999 细读这个:https://www.chinacion.cn/article/5629.html Count-Min Sketch算法,就是BloomFilter的升级版本,BloomFilter是判断一个对象存在or不存在的,Count-Min Sketch是用来记录一个对象的次数的。BloomFilter的问题,也同样存在Count-.

sinat_14913533的博客 1807

缓存框架Guava Cache部分源码分析

在本地缓存中,最常用的就是OSCache和谷歌的Guava Cache。其中OSCache在07年就停止维护了,但它仍然被广泛的使用。谷歌的Guava Cache也是一个非常优秀的本地缓存,使用起来非常灵活,功能也十分强大,可以说是当前本地缓存中最优秀的缓存框架之一。之前我们分析了OSCache的部分源码,本篇就通过Guava Cache的部分源码,来分析一下Guava Cache的实现原理。

一梦一程-记录学习点滴 5993

Guava Cache:原理详解和源码分析

原文路径:Guava Cache:原理详解和源码分析_夜雨落花的博客-优快云博客_guava缓存原理一、基础信息1、maven依赖<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>28.1-jre</version></dependency>...https://blog.csdn.n

L_D_Y_K的博客 1182

【Guava】Guava Cache的refresh和expire刷新机制

1.概述 转载:https://www.cnblogs.com/liuxiaochong/p/13613071.html 总览参考:【Guava】Google Guava本地高效缓存 2.思考和猜想 首先看一下三种基于时间的清理或刷新缓存数据的方式: expireAfterAccess: 当缓存项在指定的时间段内没有被读或写就会被回收。 expireAfterWrite:当缓存项在指定的时间段内没有更新就会被回收。 refreshAfterWrite:当缓存项上一次更新操作之后的多久会被刷新。 考虑到时

九师兄 4177

深入解析 Guava Cache

通过解析 Guava Cache 的实现原理,我们发现 Guava LocalCache 与 ConcurrentHashMap 有以下不同:ConcurrentHashMap ”分段控制并发“是隐式的(实现中没有Segment对象),而 LocalCache 是显式的。在 JDK 1.8 之后,ConcurrentHashMap 采用实现:当 put 的元素在哈希桶数组中不存在时,直接 CAS 进行写操作;在发生哈希冲突的情况下使用 synchronized 锁定头节点。

Program_san的博客 2401

AI工程化之生成式UI & A2UI(一)

本文系统介绍了生成式UI和Google A2UI技术。生成式UI通过AI直接生成前端代码(完全生成式)或DSL(混合式),实现千人千面的动态界面和研发提效。Google A2UI提出组件级和消息级协议,采用JSON规范实现渲染框架解耦,支持多端渲染。文章详细阐述了A2UI的架构设计,包括协议生成、服务端处理和渲染器实现,并对比了与传统前端框架的差异,指出A2UI本质是UI=F(AI(UI)+AI(state))的创新模式。最后通过playground项目展示了A2UI的实践应用。

qq_34306228的博客 589

训练集、验证集、测试集!YOLO系列标签数量统计!

【代码】训练集、验证集、测试集!YOLO系列标签数量统计!

qq_26281057的博客 649

Guava Cache : 本地缓存、Guava Cache介绍, API使用, 原理、CacheBuilder、常见的缓存淘汰策略

本地缓存(JVM缓存)、Guava Cache介绍, API使用, 原理、CacheBuilder

Guizy 5525

Type-c超声波切割刀

接下来,我将提供Type-C超声波切割刀项目的C代码实现示例,代码将按照上述分层架构和模块化设计进行组织。为了达到3000行以上的代码量,我将尽可能详细地实现各个模块的功能,并添加必要的注释和错误处理。通过采用分层架构和模块化设计,我们可以建立一个可靠、高效、可扩展的系统平台,为产品的成功奠定坚实的基础。实际项目中,需要更详细的硬件驱动、更完善的功能模块、更严格的测试验证和更周全的维护升级计划。针对Type-C超声波切割刀这个项目,我将从以下几个方面详细阐述最适合的代码设计架构,并提供具体的C代码实现。

lianmengde的博客 1189

高并发之——Guava Cache

最近需要用到缓存来存放临时数据,又不想采用Redis,Java自带的Map功能太少,发现Google的Guava提供的Cache模块功能很强大,于是选择使用它。 本地缓存 本地缓存作用就是提高系统的运行速度,是一种空间换时间的取舍。它实质上是一个做key-value查询的字典,但是相对于我们常用HashMap它又有以下特点: 1.并发性:由于目前的应用大都是多线程的,所以缓存需要支持并发的写...

冰河的专栏 6823

Meta开源Ego-Exo4D数据集:如何用1400小时多模态视频训练你的AI模型

Meta开源的Ego-Exo4D数据集包含1400小时多模态视频,涵盖第一人称和第三人称视角、眼动追踪、IMU传感器等多种模态,是AI模型训练的宝贵资源。本文详细介绍了从数据集下载、预处理到模型训练的全流程,帮助研究者高效利用这一多模态数据集进行AI模型开发。

weixin_29159441的博客 342

108、AWB 时间滤波器:帧间白平衡平滑,防止色彩跳变与过冲

摘要: 文章探讨了AWB(自动白平衡)时间滤波器的设计与优化,以解决帧间白平衡跳变和过冲问题。通过自适应状态机(STABLE/TRANSITION/JUMP)动态调整平滑系数alpha,结合帧率归一化和过冲保护(方向检测+限幅),实现场景切换快速响应与静态稳定性的平衡。作者分享了工程经验:避免固定阈值、联动AE/AF、真实场景验证,并推荐简化卡尔曼滤波替代IIR。最终方案在旗舰机前置摄像头中成功消除“闪白”现象,强调参数需动态适应光照与色温变化。

sundong_81的博客 64

Guava Cache expireAfterWrite 与 refreshAfterWrite区别

前面的文章缓存篇(一)- Guava有讲到Guava Cache有区别于ConcurrentHashMap的使用,就是因为其自带有自动刷新和自动失效的功能,避免我们去自己编写刷新和失效的后台线程程序。Guava Cache提供了简单便捷的api给我们使用,但是研究源码发现这里的自动刷新缓存和自动失效原理,并非是Guava Cache帮我们去添加了类似后台线程自动刷新或失效逻辑的代码,而是用另外一种...

codingtu的博客 2万+

AI大模型探索之路-应用篇11:AI大模型应用智能评估(Ragas)

随着人工智能技术的飞速发展,AI大模型(LLM)已经成为了推动技术创新和应用的关键因素。这些大模型在语言理解、图像识别、自然语言生成等领域展现出了惊人的能力。然而,随着模型规模的增大,它们对计算资源的消耗、环境适应性、模型稳定性、安全性和可解释性等方面也提出了新的挑战。因此,对AI大模型进行智能评估变得至关重要,以确保它们在实际应用中的稳定性、可靠性和有效性。本文将详细介绍Ragas框架,一个专为AI大模型设计的智能评估工具。

寻道AI,探索AI无限可能! 5546

Guava Cache 过期回源

缓存的更新有两种方法: 被动更新:先从缓存获取,没有则回源获取,再更新缓存; 主动更新:发现数据改变后直接更新缓存(在分布式场景下,不容易实现) 在高并发环境,被动回源是需要注意的。 问题:高并发场景下,大量请求在同一时间回源,大量的请求同一时间穿透到后端,容易引起后端服务崩溃(也容易引起并发问题)。 guava cache解决办法: guava cache保证单线程回源,对于同一个key,只让一个请求回源load,其他线程阻塞等待结果。同时,在Guava里可以通过配置expireAfterAcces

井底之蛙 2973

Python爬虫:爬取健身平台运动数据(跑步、骑行轨迹)

通过分析这些运动数据,用户能够了解自己的运动趋势、运动成绩,并作出相应的调整。通过使用Strava的API,我们成功地获取了用户的运动活动信息和运动轨迹数据,并进行了存储与可视化。Strava的API提供了丰富的数据接口,能够通过OAuth2认证获取用户的运动数据,包括历史数据、运动轨迹等信息。Strava的API还提供了获取活动轨迹数据的接口,返回的数据格式通常是GeoJSON格式,适用于地图可视化。随着大数据技术的发展,运动数据的分析和可视化为个人健康管理、运动训练计划的优化等提供了强大的支持。

2201_76125261的博客 1075

2025年全国青少年信息素养大赛初赛真题(算法创意实践挑战赛C++初中组:文末附答案)

2025年全国青少年信息素养大赛初赛真题(算法创意实践挑战赛C++初中组:文末附答案)

王老师青少年编程 3396

Guava cache

Guava cache,一个小巧的本地缓存使用详解

鸟哥哥的专栏 4101

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Java缓存技术-google guava cache

一、简介 guava和ehcache一样也是本地缓存,虽然都是本地缓存,但是有着不同的使用场景。guava是谷歌提供的一个Java工具包,而Guava的Cache部分提供了一套分词完善的本地存储缓存机制,在Guave之前ConcurrentMap,因为能友好的支持并发而经常被用作本地缓存,但它毕竟不具备缓存的一些特性,比如缓存过期,缓存数据加载和刷新等。   二、使用场景 1、原意消耗一些

Y-CAT的专栏 4832

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

上一篇: 关于积分系统的一点总结
下一篇: spring-data-elasticsearch中集成search Guard
@云师兄
博客等级 码龄10年 10粉丝 39原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值