一、引言
内存缓存
是一种在内存中临时存储数据的机制,它能加速数据访问,提升应用程序的响应性能。通过将经常访问的数据保存在快速访问的内存中,可以减少昂贵的磁盘或网络访问。内存缓存还能减轻数据源负载,提高系统稳定性和可扩展性。
然而,使用内存缓存需要仔细考虑缓存策略、过期时间、一致性等问题,以确保缓存的有效性。
合理的缓存设计和配置能充分发挥内存缓存的优势,提供更好的应用体验。
作为一个开发,多多少少都对内存缓存有一些了解。可能更多的人在工作中接触的更多的是memcache
、redis
这些内存缓存系统。这些系统都是需要额外部署的,需要使用客户端链接,查询和存储的时候也会增加我们的网络开销。
今天我们来认识一个基于JVM的内存缓存库:Guava Cache
。
二、Guava Cache是什么
Guava Cache是Google Guava库中提供的一个内存缓存库。旨在提供简单而高效的内存缓存解决方案。为Java开发人员提供了一种方便的方式来实现内存缓存,以改善应用程序的性能和响应性。
Guava Cache提供了一种可配置的缓存机制,可以将经常访问的数据存储在内存中,以提高数据访问的速度和性能。它支持设置缓存的最大大小、过期策略、自动加载数据等功能。缓存可以自动管理数据的过期和淘汰策略,以确保缓存中的数据是最新和有效的。
使用Guava Cache,开发人员可以轻松地在应用程序中集成内存缓存功能,以加速数据访问和提升应用程序的性能。它适用于各种本地缓存需求,并提供了简单的API和配置选项来满足不同的使用场景。通过减少对耗时的数据源访问,Guava Cache可以显著提升应用程序的响应性能,并减轻对后端资源的负载。
2.1 Guava Cache 的主要概念和特点
graph LR
A(Guava Cache 的主要概念和特点)
B(Google Guava 库中的一个功能模块)
C(简单而高效的内存缓存解决方案)
D(提高访问速度和性能)
E(配置选项)
EA(最大大小)
EB(过期策略)
EC(数据加载方式)
F(自动管理)
FA(过期和淘汰策略)
FB(数据有效性和一致性)
G(优势)
GA(API简单)
GB(减少耗时的数据源访问)
GC(提升应用程序的响应性能)
H(强大,性能改善)
A ---> B
A ---> C
A ---> D
A ---> E
E ---> EA
E ---> EB
E ---> EC
A ---> F
F ---> FA
F ---> FB
A ---> G
G ---> GA
G ---> GB
G ---> GC
A ---> H
style GB fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px
style GC fill:#FFA07A,stroke:#FFA07A,stroke-width:2px
style GA fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px
style FB fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px
style FA fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px
style EB fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px
style EC fill:#FFA07A,stroke:#FFA07A,stroke-width:2px
style EA fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px
style B fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px
style C fill:#FFA07A,stroke:#FFA07A,stroke-width:2px
style D fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px
style E fill:#98FB98,stroke:#98FB98,stroke-width:2px
style F fill:#ADD8E6,stroke:#ADD8E6,stroke-width:2px
style G fill:#00FFFF,stroke:#00FFFF,stroke-width:2px
style H fill:#E6E6FA,stroke:#E6E6FA,stroke-width:2px
-
Guava Cache 是 Google Guava 库中的一个功能模块。
-
Guava Cache 提供了简单而高效的内存缓存解决方案。
-
Guava Cache 允许将经常访问的数据存储在内存中,以提高访问速度和性能。
-
可以配置 Guava Cache 的最大大小、过期策略和数据加载方式。
-
缓存中的数据可以自动管理过期和淘汰策略,确保数据的有效性和一致性。
-
Guava Cache 适用于各种本地缓存需求,提供简单的 API 和配置选项。
-
使用 Guava Cache 可以减少对耗时的数据源访问,提升应用程序的响应性能。
-
Guava Cache 是一个简单而强大的内存缓存库,改善应用程序的性能和响应性。
三、怎么使用Guava Cache
在项目中使用Guava Cache的时候,实际是有一些固定的操作姿势,下面我们来认识一下一般情况下我们都是怎么操作的。
3.1 使用流程图
sequenceDiagram
participant A1 as Java项目
participant A as 任务线程
participant B as Guava Cache
participant C as 监听器线程
A1 ->> A1: 引入依赖
A1 ->> A: 启动任务
A ->> B: 创建Cache实例
B ->> B: 数据加载
A ->> B: 存储数据
A ->> B: 获取数据
A ->> B: 移除数据
A ->> B: 清空Cache
C ->> B: 添加监听器
C ->> B: 数据过期或者被移除逻辑
3.2 使用的详细步骤分解
添加Guava库依赖
:在你的项目中添加Guava库的依赖,以便能够使用Guava Cache。你可以从Maven中央仓库或Gradle依赖中心下载Guava相关的库文件。
com.google.guava
guava
32.1.2-jre
创建Cache实例
:使用Guava Cache提供的CacheBuilder类创建一个Cache实例。你可以通过链式调用方法来配置Cache的属性,例如最大大小、过期策略等。Cache cache = CacheBuilder.newBuilder()
.maximumSize(100)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build();
上面代码代码创建了一个具有最大大小限制和过期时间的缓存对象,我们来详细分析一下:
首选 Cache cache = CacheBuilder.newBuilder():这行代码创建了一个新的 CacheBuilder 对象,并将其分配给变量 cache。CacheBuilder 是 Guava 提供的用于构建缓存对象的构建器类。
然后 .maximumSize(100):这行代码设置了缓存的最大大小为 100。这意味着当缓存中的元素数量达到最大值时,新的元素将会替换掉最旧的元素。
其次 .expireAfterWrite(10, TimeUnit.MINUTES):这行代码设置了缓存项在写入后的存活时间为 10 分钟。换句话说,如果某个缓存项在 10 分钟内没有被读或写操作访问,那么该缓存项将会被自动移除。
最后 .build():这行代码完成了缓存对象的构建,并返回最终的 Cache 对象。
存储数据
:使用put(key, value)方法将数据存储到Cache中。你可以使用自定义的键(Key)和值(Value)类型。cache.put(key, value);
获取数据
:使用getIfPresent(key)方法从Cache中获取数据。如果数据存在于Cache中,则返回对应的值;否则返回null。Value value = cache.getIfPresent(key);
数据加载
:如果需要自动加载数据到Cache中,你可以使用get(key, Callable)方法。当缓存中不存在对应的值时,Guava Cache会自动调用提供的Callable对象来加载数据。Value value = cache.get(key, new Callable() {
public Value call() throws Exception {
// 数据加载逻辑
return loadDataByDb(key);
}
});
移除数据
:你可以使用invalidate(key)方法从Cache中移除指定的键值对。cache.invalidate(key);
清空Cache
:如果需要清空整个Cache,你可以使用invalidateAll()方法。cache.invalidateAll();
监听器
:Guava Cache还支持添加监听器,以便在数据被移除或过期时执行自定义逻辑。你可以实现RemovalListener接口并注册监听器。RemovalListener listener = new RemovalListener() {
public void onRemoval(RemovalNotification notification) {
// 执行自定义逻辑
}
};
cacheBuilder.removalListener(listener);
四、实际操作中,Google Guava的几种过期策略如何实现
Google Guava 提供了多种过期策略来管理缓存项的过期和失效。下面来介绍一下 Guava 中几种常用的过期策略及其实现方式。
老规矩,先来张图看看都有那些过期策略:
graph LR
A(Google Guava过期策略)
B(基于时间)
C(写入时间)
D(访问时间)
E(基于大小)
F(基于引用)
G(基于提醒)
A ---> B
B ---> C
B ---> D
A ---> E
A ---> F
A ---> G
style B fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px
style C fill:#FFA07A,stroke:#FFA07A,stroke-width:2px
style D fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px
style E fill:#98FB98,stroke:#98FB98,stroke-width:2px
style F fill:#ADD8E6,stroke:#ADD8E6,stroke-width:2px
style G fill:#00FFFF,stroke:#00FFFF,stroke-width:2px
4.1 基于时间的过期策略
可以通过 expireAfterWrite() 和 expireAfterAccess() 方法来设置缓存项的写入后过期时间和最后访问后过期时间。
- expireAfterWrite(duration, unit):设置缓存项在写入后的过期时间。过期时间从写入操作发生后开始计算。
Cache cache = CacheBuilder.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES) // 缓存项在写入后10分钟过期
.build();
cache.put("key", "value");
// 在10分钟内访问缓存项,它仍然有效
String value = cache.getIfPresent("key");
// 10分钟后,缓存项过期,再次访问将返回null
value = cache.getIfPresent("key");
- expireAfterAccess(duration, unit):设置缓存项在最后访问后的过期时间。过期时间从最后一次访问操作发生后开始计算。
Cache cache = CacheBuilder.newBuilder()
.expireAfterAccess(5, TimeUnit.MINUTES) // 缓存项在最后一次访问后5分钟过期
.build();
cache.put("key", "value");
// 在5分钟内多次访问缓存项,它仍然有效
String value = cache.getIfPresent("key");
value = cache.getIfPresent("key");
value = cache.getIfPresent("key");
try {
// 休眠5分钟
Thread.sleep(5 * 60 * 1000);
} catch (InterruptedException e) {
// 处理中断异常
e.printStackTrace();
}
// 5分钟后,没有再次访问缓存项,它过期并被自动移除
// 再次尝试获取缓存项将返回null
value = cache.getIfPresent("key"); // 返回null
注意:这两种策略可以根据指定的时间单位(如分钟、小时、天等)来设置过期时间。
4.2 基于大小的过期策略
可以通过 maximumSize()
方法设置缓存的最大大小限制。当缓存项数量达到最大值时,新的元素将会替换掉最旧的元素。
Cache cache = CacheBuilder.newBuilder()
.maximumSize(100) // 缓存最大容量为100
.build();
for (int i = 0; i < 150; i++) {
cache.put("key" + i, "value" + i);
}
// 在缓存容量达到100后,新的缓存项将替换最旧的缓存项
String value = cache.getIfPresent("key0"); // 返回null,因为"key0"已被替换
value = cache.getIfPresent("key100"); // 返回"value100",因为它仍然在缓存中
4.3 基于引用的过期策略
Guava 提供了 CacheBuilder
类中的 weakKeys()
和 weakValues()
方法,允许使用弱引用来存储缓存的键和值。当键或值不再被其他强引用引用时,缓存项将会被自动移除。
-
weakKeys()
:使用弱引用存储缓存的键。 -
weakValues()
:使用弱引用存储缓存的值。
这些弱引用策略可用于在内存受限的情况下,允许缓存项根据垃圾回收的需要进行回收。
Cache cache = CacheBuilder.newBuilder()
.weakKeys() // 使用弱引用存储缓存的键
.weakValues() // 使用弱引用存储缓存的值
.build();
String key = new String("key");
Object value = new Object();
cache.put(key, value);
// 当key不再有其他强引用时,缓存项将被自动移除
value = cache.getIfPresent(key); // 返回null,因为key已没有强引用
4.4 基于提醒的过期策略
通过 CacheBuilder
类的 expireAfterWrite()
方法结合 CacheBuilderSpec
类的 refreshAfterWrite()
方法,可以实现基于提醒的过期策略。该策略允许在缓存项过期时异步地加载新的值,并返回旧值。这样可以确保在缓存项过期时仍然能够返回旧值,同时异步加载新值,提高了缓存的命中率和性能。
LoadingCache cache = CacheBuilder.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES) // 缓存项在写入后10分钟过期
.refreshAfterWrite(1, TimeUnit.MINUTES) // 缓存项在写入后1分钟后异步刷新
.build(new CacheLoader() {
@Override
public String load(String key) {
return "value"; // 在缓存项过期时异步加载新的值
}
});
String value = cache.get("key");
// 10分钟内,获取缓存项将返回旧值,并异步加载新的值
value = cache.get("key");
// 10分钟后,缓存项过期,获取缓存项将返回新的值
value = cache.get("key");
五、总结
Google Guava是一个功能强大的Java工具库,提供了丰富的工具和集合类、函数式编程支持、缓存和并发处理等功能,帮助开发人员编写高效、可靠和易维护的Java代码;而且一直在维护迭代升级,行业良心。
更多操作请查看官方文档
最后:如果你从本篇文章中学到一点点东西,麻烦发财的小手点一下赞,如有疑问或者错误,欢迎提出和指正。