详解 Guava Cache

一、Guava Cache

一般在项目中,本地缓存的实现为 ConcurrentHashMap,它具有线程安全、持久有效的特点。但是相较于传统缓存,它不具备缓存过期、缓存移除等特性,Google Guava 包内的 Cache 模块可能会给你一个新的选择。

Guava 目前托管于 GitHub,在项目中引入也是十分简单:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>27.1-jre</version>
    <!-- or, for Android: -->
    <version>27.1-android</version>
</dependency>

二、初始化

2.1 CacheLoader

如果我们希望对缓存中所有的 key 值使用同一个加载策略,那么推荐使用 CacheLoader方式加载。假设我们需要缓存的数据为:

private static Map<String, List<Integer>> data = new HashMap<String, List<Integer>>() {
   
   {
   
   
    put("nanjing", new ArrayList<>(Arrays.asList(1, 3, 5, 7, 9)));
    put("beijing", new ArrayList<>(Arrays.asList(2, 4, 6, 8, 10)));
    put("shanghai", new ArrayList<>(Arrays.asList(0, -1, 11)));
}};

使用 CacheLoader 方式初始化:

LoadingCache<String, List<Integer>> cache = CacheBuilder.newBuilder()
    .maximumSize(3)
    .build(new CacheLoader<String, List<Integer>>() {
   
   
        @Override
        public List<Integer> load(String i) throws Exception {
   
   
            return data.get(i);
        }
	});

其中 maximumSize()为缓存的最大容量,当缓存超过最大容量时,基于 LRU 清理缓存。load() 方法为缓存未命中时的加载策略

同时使用 get(K) 方法进行缓存读取:

try {
   
   
	System.out.println(cache.get("nanjing"));
} catch (ExecutionException e) {
   
   
	e.printStackTrace();
}

// output: [1, 3, 5, 7, 9]

调用时优先读取缓存,如果缓存中不存在该 key 值,则调用初始化时的 load() 方法,将该 key 值存入缓存,再返回。

2.2 Callable

Callable 则是另一种较为灵活的初始化形式,它在初始化的时候不指明加载策略:

Cache<String, List<Integer>> cache2 = CacheBuilder.newBuilder().maximumSize(3).build();

在读取时再指定缓存的加载策略:

try {
   
   
	List<Integer> list = cache2.get("nanjing", new Callable<List<Integer>>() {
   
   
		@Override
		public List<Integer> call() throws Exception {
   
   
			return data.get("nanjing");
		}
	});
	System.out.println(list);
} catch (ExecutionException e) {
   
   
	e.printStackTrace();
}

// output: [1, 3, 5, 7, 9]

一般情况下,使用 CacheLoader 初始化,如果你需要更为灵活的缓存加载策略,使用 Callable 初始化。

三、初始化属性

在上一节初始化的时候使用了 maximumSize 属性,除此之外,还有这些常用属性:

属性 描述
concurrencyLevel(4) 并发级别为8,即可以同时写缓存的线程数,默认为4。
initialCapacity(10) 缓存的初始容量,默认为10
removalListener() 指定缓存的移除通知
expireAfterAccess(8, TimeUnit.SECONDS) 缓存项在给定时间内没有被读/写访问,则回收。
expireAfterWrite(8, TimeUnit.SECONDS) 缓存项在给定时间内没有被写访问(新增或覆盖),则回收。
refreshAfterWrite(8, TimeUnit.SECONDS) 缓存项在写访问(新增或覆盖)后给定时间,刷新。

四、基本操作

4.1 显式插入

Guava Cache 也支持使用 put(key, value) 方法手动的向缓存中插入数据,这会直接覆盖掉缓存中已存在的值。例如:

cache.put("guangzhou", new ArrayList<>(Arrays.asList(101, 110, 222)));

4.2 显式清除

你可以手动的清除缓存项,主要方法包括:

  • 根据 key 清除:cache.invalidate(key)
  • 批量清除:cache.invali
### Guava Cache 源码解析教程 #### 一、概述 Guava CacheGoogle 开发的一个高性能本地缓存库,适用于 Java 应用程序。该库提供了一种线程安全的方式管理内存中的键值对集合[^2]。 #### 二、核心组件介绍 ##### 1. 数据结构设计 Guava Cache 的内部实现了多种优化的数据结构用于高效存储和访问缓存项。这些数据结构的设计旨在平衡时间和空间复杂度,确保良好的性能表现[^1]。 ##### 2. 自动回收机制 不同于 `ConcurrentMap` 需要手动删除过期条目,Guava Cache 支持设置最大容量、存活时间等参数来自动生成淘汰策略,从而有效控制资源消耗。 #### 三、主要功能模块详解 ##### 1. CacheLoader 类的作用 `CacheLoader` 定义了一个抽象类,允许开发者自定义当缓存未命中时如何获取新值的方法。这使得应用程序可以根据具体需求灵活地决定加载逻辑[^3]。 ```java public class MyCustomCacheLoader extends CacheLoader<String, String> { @Override public String load(String key) throws Exception { // 实现具体的加载逻辑 return "Value for " + key; } } ``` ##### 2. LoadingCache 接口及其子类 `LoadingCache<K,V>` 继承自 `Cache<K,V>` 并增加了自动装载能力。通过实现特定的加载器(`CacheLoader`)可以构建具有懒加载特性的实例对象[^4]。 ```java LoadingCache<Object, Object> cache = CacheBuilder.newBuilder() .maximumSize(100) .expireAfterWrite(10, TimeUnit.MINUTES) .build( new CacheLoader<Object, Object>() { @Override public Object load(Object key) throws Exception { return computeExpensiveValue(key); } }); ``` #### 四、初始化方式举例 除了上述提到的 loader 方式外,还可以采用预填充的方式来创建已含有初始映射关系的缓存实例[^5]。 ```java // 使用ImmutableMap作为输入快速建立带有默认值的缓存 Cache<Integer, Integer> prepopulatedCache = CacheBuilder.<Integer, Integer>newBuilder().build(CacheLoader.from(Map.of(1, 1))); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值