使用guava作内存缓存,大多数小伙伴应该都使用过,通过CacheBuilder
创建LoadingCache
一个kv格式的缓存,如果我们需要缓存的只是一个value呢?
针对这种场景,接下来介绍一种基于Supplier
来实现的缓存方式
1. Supplier使用姿势
guava的Supplier与jdk的Supplier从接口定义上来看没什么区别,对外只提供了一个get()
方法
@FunctionalInterface @GwtCompatible public interface Supplier<T> extends java.util.function.Supplier<T> { @CanIgnoreReturnValue T get(); } 复制代码
重点需要关注的是Supplier创建的姿势,借助Suppliers
来实现
下面是几个常见的创建姿势:
memoize
: delegate为具体的获取值的委托类,需要注意的是,delegate的具体实现只会在首次时调用;这种方式相当于持久缓存memoizeWithExpiration
:delegate的返回值,会缓存一段时间;缓存时间过后,会重新调用一下delegate来获取返回值ofInstance
: 直接传参
public static <T> Supplier<T> memoize(Supplier<T> delegate) public static <T> Supplier<T> memoizeWithExpiration(Supplier<T> delegate, long duration, TimeUnit unit) public static <T> Supplier<T> ofInstance(@Nullable T instance) 复制代码
基于上面的方法描述,如果我们想实现一个10s缓存,那么可以选择memoizeWithExpiration
来实现
AtomicInteger atomicInteger = new AtomicInteger(1); Supplier<Integer> cache = Suppliers.memoizeWithExpiration(this::ret, 10, TimeUnit.SECONDS); private int ret() { System.out.println("------- 更新 value --------"); return atomicInteger.getAndAdd(2) ; } 复制代码
上面定义了一个内存缓存cache
, 缓存10s,调用时若缓存失效,会重新调用ret()
刷新缓存
测试case就比较简单了
@Test public void testSupplier() throws InterruptedException { for (int i = 0; i < 10; i++) { System.out.print(cache.get() + " | "); } System.out.println(); Thread.sleep(10000); System.out.println(cache.get()); } 复制代码
输出如下
------- 更新 value -------- 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ------- 更新 value -------- 3 复制代码
2. 缓存刷新
使用Supplier当缓存时,需要注意的一点就是没有缓存失效的方法可供调用;对于LoadingCache
若是想失效缓存,可以通过调用 invalidate
来主动失效指定的缓存,那么Supplier 可以怎么整?
- 直接重新赋值
比如当我们希望刷新时,可以直接覆盖就的supplier即可
public void refresh() { cache = Suppliers.memoizeWithExpiration(this::ret, 10, TimeUnit.SECONDS); }