惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

宝玉的分享
宝玉的分享
酷 壳 – CoolShell
酷 壳 – CoolShell
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
S
Security @ Cisco Blogs
小众软件
小众软件
D
Docker
博客园_首页
A
About on SuperTechFans
P
Privacy International News Feed
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
A
Arctic Wolf
Spread Privacy
Spread Privacy
有赞技术团队
有赞技术团队
T
Tailwind CSS Blog
Latest news
Latest news
WordPress大学
WordPress大学
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
T
The Exploit Database - CXSecurity.com
C
Cybersecurity and Infrastructure Security Agency CISA
大猫的无限游戏
大猫的无限游戏
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
K
Kaspersky official blog
V2EX - 技术
V2EX - 技术
SecWiki News
SecWiki News
U
Unit 42
GbyAI
GbyAI
H
Hackread – Cybersecurity News, Data Breaches, AI and More
L
LINUX DO - 热门话题
S
Security Affairs
Y
Y Combinator Blog
aimingoo的专栏
aimingoo的专栏
Blog — PlanetScale
Blog — PlanetScale
MongoDB | Blog
MongoDB | Blog
博客园 - 【当耐特】
The GitHub Blog
The GitHub Blog
T
Tenable Blog
W
WeLiveSecurity
Cloudbric
Cloudbric
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
G
Google Developers Blog
Application and Cybersecurity Blog
Application and Cybersecurity Blog
N
Netflix TechBlog - Medium
F
Full Disclosure
N
News and Events Feed by Topic
D
DataBreaches.Net
P
Proofpoint News Feed
B
Blog RSS Feed
B
Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org

XINDOO

关于内卷,几个值得深想的洞察 当创作被 Skill 化:我用 AI 写了一部 320 章的长篇网文 AI第一剑,先斩程序员 AI 也会偷懒?这个 PUA 工具专治“摸鱼式编程” Gstack 深度解析:YC CEO 开源的 AI 工程团队 GitHub Trending霸榜!深度解析AI Coding辅助神器 Superpowers 深度探讨:从 OpenClaw 爆火,看 AI Agent 的真相与程序员的未来 我复刻了NotebookLM的信息图功能 我用AI写了部小说,这里是整个过程 [翻译]我在谷歌14年学到的21堂课 2万字吊打40万字:为什么我的“牛马Agent”比“数字分身”更聪明? 最近AI领域爆火的 Agent Skills 是什么? 从计算机科学的视角来看拖延症 一周改6个库后我悟了:AI时代,程序员正在退化成“甲方” 使用n8n做一个自动同步更新的Github项目问答机器人 Agent设计模式——第 20 章:优先级排序 Agent设计模式——第 1 章:提示词链 Agent设计模式——附录 D - 使用 AgentSpace 构建 Agent Agent设计模式——第 19 章:评估和监控 Agent设计模式——第 10 章:模型上下文协议 (MCP) Agent设计模式——第 21 章:探索和发现 Agent设计模式——智能体设计模式 Agent设计模式——第 11 章:目标设定和监控 Agent设计模式——第 9 章:学习和适应 Agent设计模式——第 16 章:资源感知优化 Agent设计模式——附录 G - 编码 Agent Agent设计模式——第 13 章:人机协同 Agent设计模式——第 17 章:推理技术 Agent设计模式——附录 F - 深入剖析:Agent 推理引擎的内部运作机制 Agent设计模式——章节目录 Agent设计模式—— Agent设计模式——第 7 章:多 Agent 协作 Agent设计模式——附录 E - 命令行界面中的 AI Agent Agent设计模式——附录 C - Agentic 框架快速概览 Agent设计模式——第 3 章:并行化 Agent设计模式——**常见问题解答:Agentic 设计模式** Agent设计模式——第 14 章:知识检索(RAG) Agent设计模式——第 18 章:Guardrails/安全模式 Agent设计模式——第 15 章:Agent 间通信(A2A) Agent设计模式——第 8 章:内存管理 Agent设计模式——第 12 章:异常处理和恢复 Agent设计模式——第 4 章:反思 Agent设计模式——附录 B - AI Agentic 交互:从图形界面到现实世界环境 Agent设计模式——第 5 章:工具使用(函数调用) Agent设计模式——结论 Agent设计模式——第 6 章:规划 Agent设计模式——第 2 章:路由 从经验主义到贝叶斯理论:如何排查线上问题 我用AI为自己造了一把安全的开发者“瑞士军刀”” 从LLM和MCP的协同过程看如何做优化 打通Dify与AI工具生态:将Workflow转为MCP工具的实践 一文了解知识库背后的技术RAG AI应用的五个级别:从入门到专家的进阶之路 一文入门AI圈最近爆火的MCP协议 HTTP/3:性能改进(第 2 部分) deepseek-r1祛魅:从过度热捧到理性认知⁠ 为什么AI智能体需要工作流 如何用GPT-4o解读视频 json命令行处理神器jq介绍 OpenAI的结构化浅析 从大模型的原理到提示词优化 从经济学原理看团队分工合作 [翻译]关于人工智能的30个思考 从马斯洛需求层次理论谈职场激励 知识与智慧 如何使用大语言模型绘制专业图表 两个开源项目打造自己的大模型聚合平台 我让gpt4o给我推荐了一千多次书 得到了这些数据 用Langchain创建一个可以总结网页内容的Agent 推荐一个好用的命令行工具ShellGPT 关于ffmpeg height not divisible by 2的错误 使用Certbot解决https证书自动更新的问题 Spring Cache简明教程 软件开发中的抓大放小vs极致细节思维 OpenAI Assistants-API简明教程 OpenAI的多函数调用(Multiple Function Calling)简介 如何使用ffmpeg制作透明背景的视频 spring-kafka中ContainerProperties.AckMode详解 如何在地图上寻找最密集点的位置? IO密集型服务提升性能的三种方法 职场中的基本归因错误和自利归因 使用javax.validation.constraints校验参数合法性 Java Optional:让你的代码更优雅 ChatGPT函数调用初体验:让ChatGPT具备抓取网页文本的能力 如何使用ChatGPT提升自己的“码”力? 使用ffmpeg拼接两张图片 ThreadPoolExecutor——高效处理并发任务的必备良器 从CPU的视角看 多线程代码为什么那么难写! 使用ffmpeg缩小视频体积的几种方式 Linux parallel 命令使用手册 为什么说过早优化是万恶之源? Linux xargs命令介绍 深入理解Spring的事件通知机制 Java高并发之CyclicBarrier简介 聊一聊过度设计! 详解Redisson分布式限流的实现原理 Java中使用HashMap时指定初始化容量性能一定会更好吗? 如何用ffmpeg截取视频片段&截取时间不准确的坑 XINDOO的2022年年终总结 使用ffmpeg将视频转成HLS(m3u8)格式
谷歌Guava LoadingCache介绍
2022-10-07 · via XINDOO

在这里插入图片描述

  在工作中,加Cache是非常常见的一种性能优化手段,操作系统底层、计算机硬件层为了性能优化加了各种各样的Cache,当然大多数都是对应用层透明的。但如果你想在应用层加Cache的话,可能就需要你自己实现了。

  其实在Java环境下,Cache有各种各样的选择,比如最初级的你可以直接用HashMap实现一个Cache,不过你得自己关注下数据加载和淘汰的策略。更高级的有像spring-cache,代码都不需要改,只需要简单加几个注解就可以实现对关键数据的缓存,相当方便(后续我也会出一篇博客介绍下spring-cache)。 今天我们要介绍的是谷歌guava包中的LoadingCache, 也是功能完善,简单好用。

  LoadingCache是Guava包中提供一个一种本地Cache,本地Cache的优势就是没有网络IO,速度快。但劣势也很明显,Cache容量受限于本地内存大小,Cache中的数据没法共享。所以它就只适合少量热点数据的缓存,其使用方法也很简单,我们拿maven为例,你只需要添加一下Maven依赖即可引入guava包:

<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>31.1-jre</version>
</dependency>

使用代码也非常简单,如下:

    private static LoadingCache<String, String> cache =
            CacheBuilder.newBuilder()
                        // 初始化容量
                        .initialCapacity(4)
                        // 缓存池大小,在缓存数量到达该大小时, Guava开始回收旧的数据
                        .maximumSize(8)
                        // 设置时间对象没有被读/写访问则对象从内存中删除(在另外的线程里面不定期维护)
                        .expireAfterAccess(5, TimeUnit.SECONDS)
                        // 设置缓存在写入之后 设定时间 后失效
                        .expireAfterWrite(5, TimeUnit.SECONDS)
                        // 数据被移除时的监听器, 缓存项被移除时会触发执行
                        .removalListener((RemovalListener<String, String>) rn -> {
                            System.out.println(String.format("数据key:%s value:%s 因为%s被移除了", rn.getKey(), rn.getValue(),
                                    rn.getCause().name()));
                        })
                        // 开启Guava Cache的统计功能
                        .recordStats()
                        // 数据写入后被多久刷新一次
                        .refreshAfterWrite(5, TimeUnit.SECONDS)
                        // 数据并发级别
                        .concurrencyLevel(16)
                        // 当缓存中没有数据时的数据加载器
                        .build(new CacheLoader<String, String>() {
                            @Override
                            public String load(String key) throws Exception {
                                return key + "_" + System.currentTimeMillis();
                            }
                        });

  然后我们就可以直接在代码的其他地方用cache.get("myKey") 来愉快地使用LoadingCache了,它会主动加载数据,并在存储空间不够或者数据过期时清理掉不需要的数据,非常省心且方便。

这里有些重点参数,下面详细介绍下:

参数 作用 注意事项
maximumSize 缓存的k-v最大数据,当总缓存的数据量达到或者快达到这个值时,就会淘汰它认为不太用的一份数据,近似LRU或者LFU策略 并不一定是达到这个值才开始淘汰旧数据,可能接近时就会开始淘汰
expireAfterAccess 数据被访问后多久就会过期,这个策略主要是为了淘汰长时间不被访问的数据 数据过期不是立即淘汰,而是有数据访问时才会触发
expireAfterWrite 数据写入后多久过期,这个策略是为了防止旧数据被缓存过久 同上
refreshAfterWrite 数据写入后多久刷新一次,这个类似于expireAfterWrite,但它会主动更新数据 同上
concurrencyLevel 数据的并发级别,LoadingCache为了实现线程安全,它里面采用了类似Java7中ConcurrentHashMap的实现,采用了分段加锁的方式,分段数影响了它的最大并发量
recordStats 开启Cache的状态统计(默认是开启的) 开启这个是会影响到性能的,如果要求极致性能的话关注下个

  我们来重点介绍下CacheLoader CacheStats和RemovalListener,因为这三者涉及到了数据的加载、使用和删除的完整生命周期,先来看下CacheLoader。

CacheLoader

  CacheLoader的作用就是为了在Cache中数据缺失时加载数据,其中最重要的方法就是load()方法,你可以在load() 方法中实现对应key加载数据的逻辑。在调用LoadingCache的get(key)方法时,如果key对应的value不存在,LoadingCache就会调起你在创建cache时传入的CacheLoader的load方法。

CacheStats

在这里插入图片描述

  使用CacheStats cacheStats = cache.stats(); 我就可以获取到cache的stats数据。从cacheStats中我们可以看到cache的命中率、命中数、异常率、加载时延……等数据,通过这些数据就可以直观地看出我们cache的一些性能指标,如果做出一些参数调整。 比如如果命中率过低,我们是不是可以调整大下maximumSize,或者调整下数据的过期策略?

RemovalListener

  RemovalListener会在LoadingCache中数据被清理时调起,其实就是个监听器模式,这样你可以通过Listener实现对数据淘汰事件的监听,比如在数据淘汰时打一行日志啥的。使用方法也很简单,在Java8+上你可以直接使用lambda表达式,或者也可以自己实现RemovalListener接口,并在构建Cache时注册进去即可。

public enum RemovalCause {
  EXPLICIT {
    @Override
    boolean wasEvicted() {
      return false;
    }
  },
  REPLACED {
    @Override
    boolean wasEvicted() {
      return false;
    }
  },

  COLLECTED {
    @Override
    boolean wasEvicted() {
      return true;
    }
  },
  EXPIRED {
    @Override
    boolean wasEvicted() {
      return true;
    }
  },

  SIZE {
    @Override
    boolean wasEvicted() {
      return true;
    }
  };
  abstract boolean wasEvicted();
}

  在RemovalListener内,我们可以通过RemovalListener获取到被删除的数据的key和value,也可以知晓数据被删除的原因。可以看到有个RemovalCause枚举类,详细说明了几种数据被清除的原因,比如被用户主动删除(RemovalCause.EXPLICIT),被替换(RemovalCause.REPLACED),过期淘汰(RemovalCause.EXPIRED),被GC收集器删除(RemovalCause.COLLECTED),容量不够导致的删除(RemovalCause.SIZE)。


   关于LoadingCache的介绍就到这了。再说下谷歌的guava包,其实guava是一个很好用的Java开源开发包,里面除了cache之外,还有各种集合工具、并发工具,Cache只是其中很小的一部分,后续有机会我们在详细探索下guava。今天的文章就到这了,大家觉得有用请点赞,喜欢请关注。

xindoo

10+年技术博主,博客专家,曾就职于阿里 小米,目前任贝壳资深工程师。拥有运维、搜索广告、后端业务相关工作经验,擅长Java、Lniux、Redis……