Appearance
Java Caffeine 库介绍
1. 简介
是一个高性能的 Java 本地(内存)缓存库,专为 Java 8+ 设计,提供接近最优的缓存命中率。它由 Ben Manes(前 Guava Cache 贡献者)开发,是 Guava Cache 的继任者,使用 Guava 风格的 API,但性能更优、功能更丰富。
Caffeine 采用 Window TinyLFU (W-TinyLFU) 驱逐算法,结合频率(LFU)和最近使用(LRU),命中率远超传统 LRU。
与 Guava 对比:
| 特性 | Caffeine | Guava Cache |
|---|---|---|
| 驱逐算法 | Window TinyLFU(近最优) | LRU |
| 异步加载 | 支持 CompletableFuture | 不支持 |
| 性能 | 更快(读写均优) | 较慢 |
| 内存效率 | 更高 | 一般 |
| 推荐 | 首选 | 迁移到 Caffeine |
其他优势:ConcurrentHashMap)、统计监控、小内存占用、弱引用/软引用。
2. 快速上手
2.1. Maven 依赖
XML
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>3.2.3</version>
</dependency>2.2. 基本使用示例
简单缓存:最大 1000 条,写后 10 分钟过期
JavaCache<String, String> cache = Caffeine.newBuilder() .maximumSize(1000) .expireAfterWrite(10, TimeUnit.MINUTES) .build(); cache.put("key1", "value1"); System.out.println(cache.getIfPresent("key1")); // value1 System.out.println(cache.get("key2", key -> "default value")); // default value自动加载的缓存
JavaLoadingCache<String, String> cache = Caffeine.newBuilder() .maximumSize(1000) .build(key -> "Hello " + key); // Loader System.out.println(cache.get("world")); // Hello world // 统计 cache.recordStats(); System.out.println(cache.stats().hitRate()); // 命中率
2.3. Spring Boot 集成
application.yml配置:YAMLspring: cache: type: caffeine caffeine: spec: maximumSize=500,expireAfterWrite=600s启用:在启动类上添加
@EnableCaching注解;缓存管理
Java@Service public class UserService { @Cacheable("users") // 自动缓存 public User getUser(Long id) { return userRepository.findById(id); } @CacheEvict("users") // 清除缓存 public void deleteUser(Long id) { ... } }1
2
3
4
5
6
7
8
9
10
3. 高性能的原因
3.1. W-TinyLFU 算法
Caffeine 使用 Window-TinyLFU (W-TinyLFU) 算法,这是它性能优越的核心原因之一:
传统 LRU 的问题: LRU 只考虑访问时间,容易被突发流量击穿,导致缓存污染;
LFU 的问题: 需要维护精确的访问频率计数器,内存开销大;
W-TinyLFU 的优势:
- 使用 Count-Min Sketch 数据结构,用极小的内存(约几十 KB)近似统计访问频率;
- 分为 Window 区和 Main 区:
- Window 区:占 1 ~ 20%,用 LRU 保护新数据;
- Main 区:占 80 ~ 99%,分为 Protected、Probation,用 TinyLFU 决定对象的晋升/替换;
- 能有效应对突发流量,同时保护长期热点数据;
- 命中率通常比 LRU 高 10-20%。
TinyLFU 不是精确计数频率,而是用一个近似计数器(Count-Min Sketch)来估算访问频率:
- 每次访问某个 Key 时,更新其在 Sketch 中的计数;
- 查询时能快速得到一个近似访问频率;
- 通过周期性衰减(Aging)防止旧热点 “占坑” 太久。
这样,它能在
3.2. 基于 ConcurrentHashMap
ConcurrentHashMap 是一个基于数组 + 链表/红黑树结构,使用 CAS + synchronized 分段锁 + 并行扩容的高性能并发哈希表。
3.3. 异步化写入机制
Caffeine 采用完全异步的写入策略,避免阻塞调用线程:所有的维护操作(淘汰、过期清理等)都异步执行读写操作只是记录到缓冲区,不会立即执行昂贵的维护操作。
3.4. 懒惰删除策略
- 不立即删除过期条目: 过期条目不会立即被清理,而是在读写时懒惰删除;
- 批量清理: 积累一定数量后批量处理,减少开销;
- 摊还成本: 将删除成本分摊到多次操作中。
3.5. 弱引用和软引用支持
Java
Caffeine.newBuilder()
.weakKeys() // 允许 GC 回收 key
.softValues() // 内存不足时可回收 value
.build();