Caffeine / Guava Cache ?一篇文章带你了解
在 Java 后端开发中,本地缓存(Local Cache) 是非常常见的性能优化手段。
当系统频繁访问数据库或远程服务时,可以通过缓存减少 IO 开销,提高系统吞吐量。
在 Java 生态中,最常见的本地缓存方案主要有两个:
Guava Cache Caffeine
很多面试中也经常会问:
-
Guava Cache 和 Caffeine 有什么区别?
-
为什么现在很多项目更推荐使用 Caffeine?
-
Caffeine 为什么性能更高?
本文带你系统了解 Guava Cache 和 Caffeine 的原理与区别。
一、本地缓存是什么
本地缓存(Local Cache) 指的是将数据缓存在 应用进程的 JVM 内存中。
典型访问流程:
请求 → 本地缓存 → Redis / 数据库
如果缓存命中,就可以直接返回数据,从而避免访问数据库。
优点
-
访问速度极快(内存级)
-
减少数据库压力
-
降低系统延迟
缺点
-
只在当前 JVM 内有效
-
多实例部署时缓存不共享
因此本地缓存通常用于:热点数据缓存、配置缓存、读多写少的数据
二、Guava Cache 简介
Guava Cache 是 Google 在 Guava 工具库中提供的一个本地缓存实现。
它提供了一套非常简单易用的缓存 API。
基本使用
Cache<String, String> cache = CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build();
cache.put("key", "value");
String value = cache.getIfPresent("key");
Guava Cache 常见特性
1 自动加载
可以使用 LoadingCache 实现自动加载。
LoadingCache<String, String> cache = CacheBuilder.newBuilder()
.maximumSize(1000)
.build(new CacheLoader<String, String>() {
@Override
public String load(String key) {
return loadFromDb(key);
}
});
String value = cache.get("key");
当缓存不存在时,会自动调用 load() 方法加载数据。
2 过期策略
Guava 支持两种常见过期策略:
-
expireAfterWrite:写入后过期 -
expireAfterAccess:访问后过期
3 缓存大小限制
可以通过 maximumSize 限制缓存最大数量,防止缓存无限增长。
4 移除监听
Guava 支持缓存移除监听:
.removalListener(notification -> {
System.out.println("key removed: " + notification.getKey());
})
当缓存被淘汰或过期时,可以执行回调逻辑。
三、Guava Cache 的问题
虽然 Guava Cache 非常好用,但在高并发场景下也暴露了一些问题。
1 锁竞争问题
Guava Cache 使用 Segment 分段锁机制。
在高并发情况下容易出现:
-
线程竞争锁
-
性能下降
2 淘汰算法较简单
Guava 使用的是 LRU 近似算法。
只考虑最近访问时间,没有考虑访问频率,因此命中率并不是最优。
3 官方不再持续优化
Guava Cache 目前基本进入 维护状态。
很多新项目已经转向使用 Caffeine。
四、Caffeine 简介
Caffeine 是 Guava Cache 作者 Ben Manes 重新设计的一款高性能本地缓存库。
GitHub 地址:
https://github.com/ben-manes/caffeine
Caffeine 的目标是:构建 Java 中性能最好的本地缓存库。
在官方 Benchmark 中,Caffeine 的性能通常是 Guava Cache 的数倍。
五、Caffeine 基本使用
Caffeine 的 API 与 Guava 非常类似,因此迁移成本非常低。
基础示例
Cache<String, String> cache = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build();
cache.put("key", "value");
String value = cache.getIfPresent("key");
自动加载
LoadingCache<String, String> cache = Caffeine.newBuilder()
.maximumSize(1000)
.build(key -> loadFromDb(key));
String value = cache.get("key");
异步缓存
Caffeine 支持 异步加载缓存:
AsyncLoadingCache<String, String> cache =
Caffeine.newBuilder()
.maximumSize(1000)
.buildAsync(key -> loadFromDb(key));
适用于:
-
RPC 请求
-
IO 密集型任务
-
远程接口调用
六、Caffeine 为什么这么快
1 W-TinyLFU 淘汰算法
传统缓存淘汰算法:
| 算法 | 特点 |
|---|---|
| FIFO | 不考虑访问频率 |
| LRU | 只考虑最近访问 |
| LFU | 统计成本高 |
Caffeine 使用 W-TinyLFU(Window TinyLFU)。
核心思想:
结合 LRU + LFU
策略:
-
新数据先进入 Window 区(LRU)
-
高频访问数据进入 Main 区(LFU)
-
淘汰低频数据
这样可以显著提升缓存命中率。
2 无锁读设计
Guava 使用 Segment Lock。
而 Caffeine 使用:
-
CAS
-
无锁数据结构
因此可以减少锁竞争,在高并发环境下性能更好。
3 高效数据结构
Caffeine 内部使用了多种高性能结构,例如:
-
RingBuffer
-
ConcurrentHashMap
-
CAS 原子操作
从而保证高并发下依然保持高性能。
七、Guava Cache vs Caffeine
| 对比 | Guava Cache | Caffeine |
|---|---|---|
| 发布时间 | 较早 | 较新 |
| 并发性能 | 一般 | 很高 |
| 淘汰算法 | LRU | W-TinyLFU |
| 锁机制 | Segment Lock | CAS + 无锁 |
| 异步支持 | 不支持 | 支持 |
| 官方推荐 | 维护状态 | 推荐使用 |
总结一句话:
Caffeine 可以看作 Guava Cache 的升级版。
八、Spring Boot 中使用 Caffeine
Spring Boot 对 Caffeine 有官方支持。
引入依赖:
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
配置 CacheManager:
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager manager = new CaffeineCacheManager();
manager.setCaffeine(Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES));
return manager;
}
使用缓存:
@Cacheable("user")
public User getUser(Long id) {
return userMapper.selectById(id);
}
九、常见应用场景
Caffeine 在实际项目中常见的使用场景包括:
1 热点数据缓存
例如:用户信息、商品信息、系统配置
2 本地缓存 + Redis 多级缓存
常见架构:
请求 → Caffeine → Redis → 数据库
这样可以:减少 Redis 压力和降低访问延迟
3 防止缓存击穿
对于热点 Key,可以先使用本地缓存挡住大量请求。
十、总结
Guava Cache 和 Caffeine 都是 Java 常用的本地缓存库。
但随着高并发场景的增多:
Caffeine 已经逐渐成为主流选择。
主要原因包括:
-
更高并发性能
-
更先进的淘汰算法
-
更丰富的功能(异步缓存)
因此在新项目中,一般推荐直接使用 Caffeine。
如果这篇文章对你有帮助,欢迎点个赞 👍
后续会持续更新 Java 后端高频技术解析系列。

更多推荐




所有评论(0)