Guava 缓存库 Cachebuilder 使用和原理
简介
CacheBuilder 是 Guava 缓存库(Google 提供的一个 Java 工具库)中的一个类,用于创建和配置缓存实例。
Guava 缓存库提供了一套强大且易用的缓存解决方案,可以帮助开发者轻松地添加缓存功能以提高程序性能。而 CacheBuilder 是其中一个关键的构建器类,它提供了多种方法用于配置和创建缓存实例。
下面是 CacheBuilder 的一些主要特点和功能:
链式调用:CacheBuilder 允许通过链式调用方法来配置缓存的各项参数,使得配置变得简洁明了。
缓存大小限制:可以通过 maximumSize(long) 方法指定缓存的最大容量,当缓存超过指定容量时,会按照一定的策略(例如LRU)进行缓存项的清理。
过期时间设置:使用 expireAfterWrite(duration, unit) 方法可以为缓存项设定写入后过期时间,即在一定时间后自动从缓存中移除。
弱引用键或值:可以使用 weakKeys() 和 weakValues() 方法将缓存的键或值设置为弱引用,这样当没有其他强引用指向它们时,垃圾回收器可以自动回收这些对象。
定时刷新:使用 refreshAfterWrite(duration, unit) 方法可以为缓存项设置定时刷新,即在一定时间后自动更新缓存项的值,避免了缓存过期时的数据加载延迟。
统计信息:CacheBuilder 提供了统计缓存命中率等信息的功能,可以通过 recordStats() 方法开启统计,并通过 Cache.stats() 方法获取统计信息。
自定义缓存加载器:可以通过 build(CacheLoader) 方法传入自定义的缓存加载器,用于指定缓存项的加载逻辑。
使用实例
public class CacheTest {
LoadingCache<String, String> cache = CacheBuilder.newBuilder()
.maximumSize(10000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.expireAfterAccess(10, TimeUnit.MINUTES)
.build(
new CacheLoader<String, String>() {
@Override
public String load(String String) {
return "value-"+ LocalTime.now();
}
}
);
public static void main(String[] args){
CacheTest cacheTest = new CacheTest();
System.out.println(cacheTest.getV("aa"));
System.out.println(cacheTest.getV("bb"));
System.out.println(cacheTest.getV("aa"));
}
public String getV(String key){
try {
return cache.get(key);
} catch (ExecutionException e) {
e.printStackTrace();
}
return "null";
}
}
基本原理
数据存储和查询
Guava 缓存库的数据存储主要分了两级,第一级是 Segment ,第二级是 AtomicReferenceArray
Segment 是 Guava 实现的 LocalCache 的子类,LocalCache 中有一个 Segment 数组 segments ,对于每一个缓存的键值 key ,都可以通过 key 的hash找出唯一的Segment
Segment 中有一个 AtomicReferenceArray 类型变量 table,table 的元素类型是 ReferenceEntry , ReferenceEntry 是Guava对缓存值的包装类型,并包含了缓存的访问时间,写入时间等信息
查询时:先通过key的hash定位到一个Segment,segments 数组中的每个元素是在LocalCache被创建时就初始化好的。再从 Segment 的 table 中遍历查找 hash 和 key 的hash相同的元素链表,再遍历链表使用类似 equals 方法找到最终的缓存值。查找过程除 Segment 外类似 hashmap 。Segment的作用类似 concurrenthashMap 中Segment 的作用,都是为了提高并发度。 若没有找到值,则调用使用者自定义的 CacheLoader 类中的 load() 方法加载缓存。
过期和刷新
Guava 缓存好用的特点之一是提供了各种缓存过期和刷新策略,其基本原理是缓存包装类 ReferenceEntry 中记录了缓存值的各种时间,如创建时间,访问时间。在查询到缓存值后,对比当前时间与这些时间的差值和使用者设置的过期时间,若超时则重新调用缓存加载方法加载新缓存。