介绍
Caffeine 是一个基于 Java 8 开发的高性能本地缓存库,由 Ben Manes 开发,旨在作为 Google Guava Cache 的现代化替代品。它凭借极致的性能和超高的缓存命中率,被广泛应用于 Spring Boot、Hibernate 等主流框架中,被誉为 Java 本地缓存的首选方案。
🚀 核心优势:为何选择 Caffeine?
与 Guava Cache 或 ConcurrentHashMap 相比,Caffeine 在性能和功能上都有显著优势:
- 极致的读写性能:通过高度优化的并发控制,其读写吞吐量远超同类框架,读操作性能接近原生的
ConcurrentHashMap。 - 超高的缓存命中率:核心在于其先进的缓存淘汰算法,能有效识别并保留热点数据。
- 丰富的功能特性:支持多种过期策略、异步加载、缓存统计等,功能完备且配置灵活。
- 轻量级无依赖:核心包体积小,无任何第三方依赖,可轻松集成到项目中。
以下是 Caffeine 与 Guava Cache 的核心特性对比:
| 特性 | Caffeine | Guava Cache |
|---|---|---|
| 淘汰算法 | ✅ Window TinyLFU (命中率更高) | LRU 近似 |
| 性能 | ⚡ 极高 (接近理论最优) | 良好 |
| 异步加载 | ✅ AsyncLoadingCache |
❌ |
| 社区活跃度 | 🌟 持续更新 | 🛑 维护模式 |
🧠 核心原理:W-TinyLFU 算法
Caffeine 高性能的灵魂在于其采用的 W-TinyLFU (Window TinyLFU) 缓存淘汰算法。该算法巧妙地结合了 LFU (Least Frequently Used) 和 LRU (Least Recently Used) 的优点,解决了传统算法的痛点:
- 解决 LRU 的“缓存污染”问题:LRU 仅关注数据的最近访问时间,当有大量低频数据突然涌入时,容易将真正的热点数据挤出缓存。
- 解决 LFU 的“数据僵化”问题:LFU 仅关注数据的访问频率,导致一些历史上高频但当前已不再访问的数据长期驻留缓存,无法被淘汰。
W-TinyLFU 通过“窗口缓存”对新数据进行频率预热,再结合频率过滤机制,既能快速接纳新的热点数据,又能有效剔除低频无效数据,从而在各种访问模式下都能保持极高的缓存命中率。
🛠️ 核心特性详解
Caffeine 提供了丰富且强大的功能,以满足不同业务场景的需求。
灵活的驱逐与过期策略
Caffeine 支持多种策略来自动管理缓存空间,防止内存溢出。
- 基于容量驱逐:当缓存条目数量达到预设最大值时,自动淘汰“价值最低”的数据。
.maximumSize(10_000) // 最多缓存 10,000 个条目 - 基于权重驱逐:可以为每个缓存条目定义权重(如对象大小),当总权重超限时触发驱逐。
.maximumWeight(100_000) .weigher((String key, Data value) -> value.sizeInBytes()) - 基于时间过期:
expireAfterWrite: 写入后固定时间过期。expireAfterAccess: 最后一次访问后固定时间过期。expireAfter: 支持自定义每个条目的过期时间。
多样的缓存加载模式
- 手动加载 (
Cache):适用于需要显式put/get的场景。Cache<String, Object> cache = Caffeine.newBuilder().build(); cache.put("key", "value"); Object val = cache.getIfPresent("key"); - 同步加载 (
LoadingCache):当查询的键不存在时,自动调用加载函数来获取数据,避免缓存穿透。LoadingCache<String, String> cache = Caffeine.newBuilder() .build(key -> fetchDataFromDB(key)); String value = cache.get("userId"); // 若缓存未命中,自动调用加载函数 - 异步加载 (
AsyncLoadingCache):基于CompletableFuture实现,在高并发场景下不阻塞调用线程,是性能最佳实践。AsyncLoadingCache<String, String> cache = Caffeine.newBuilder() .buildAsync(key -> CompletableFuture.supplyAsync(() -> fetchDataFromDB(key))); CompletableFuture<String> future = cache.get("userId");
其他实用功能
- 缓存统计 (
recordStats):开启后可以获取缓存命中率、加载时间、驱逐次数等关键指标,便于监控和调优。 - 移除监听器 (
removalListener):当数据因驱逐、过期或手动删除而被移除时,可以注册监听器接收通知。 - 引用类型 (
weakKeys/softValues):支持弱引用或软引用,当 JVM 内存不足时,GC 可以回收这些对象,有效防止内存泄漏。
使用
添加 Maven 依赖
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>3.2.0</version> <!-- 请使用最新版本 -->
</dependency>
创建并使用缓存
import com.github.benmanes.caffeine.cache.Cache;
import java.util.concurrent.TimeUnit;
public class CaffeineExample {
public static void main(String[] args) {
// 构建一个缓存
Cache<String, String> cache = Caffeine.newBuilder()
.maximumSize(100)
.expireAfterWrite(5, TimeUnit.MINUTES)
.recordStats()
.build();
// 存入数据
cache.put("key1", "value1");
// 获取数据
String value = cache.getIfPresent("key1");
System.out.println(value); // 输出: value1
// 获取或计算 (如果不存在则执行函数并放入缓存)
String value2 = cache.get("key2", k -> "computed-" + k);
System.out.println(value2); // 输出: computed-key2
// 查看统计信息
System.out.println(cache.stats());
}
}