Guava中Cache的使用

时间:2020-11-28 20:44:48

缓存的主要作用是暂时在内存中保存业务系统的数据处理结果,并且等待下次访问使用。在日常开发的很多场合,由于受限于硬盘IO的性能或者我们自身业务系统的数据处理和获取可能非常费时,当我们发现我们的系统这个数据请求量很大的时候,频繁的IO和频繁的逻辑处理会导致硬盘和CPU资源的瓶颈出现。缓存的作用就是将这些来自不易的数据保存在内存中,当有其他线程或者客户端需要查询相同的数据资源时,直接从缓存的内存块中返回数据,这样不但可以提高系统的响应时间,同时也可以节省对这些数据的处理流程的资源消耗,整体上来说,系统性能会有大大的提升

Guava中Cache的两种创建方式

在Guava中可以通过cacheLoader和callable callback两种方式来创建缓存。通过这两种方法创建的cache,和通常用map来缓存的做法比,不同在于,这两种方法都实现了一种逻辑——从缓存中取key X的值,如果该值已经缓存过了,则返回缓存中的值,如果没有缓存过,可以通过某个方法来获取这个值。但不同的在于cacheloader的定义比较宽泛,是针对整个cache定义的,可以认为是统一的根据key值load value的方法。而callable的方式较为灵活,允许你在get的时候指定。

cacheLoader方式

测试代码

@Test
public void testLoadingCache() throws Exception {
LoadingCache<String, String> cahceBuilder = CacheBuilder.newBuilder().build(new CacheLoader<String, String>() {
@Override
public String load(String key) throws Exception {
System.out.println("请求的key为" + key + "在缓存中不存在,通过load方法获取key.");
String strProValue = "hello " + key + "!";
return strProValue;
}

});

// 第一次到缓存里面key为peida的数据,缓存不存在通过,load加载,并保存到缓存里面
System.out.println("a value:" + cahceBuilder.get("a"));
// 第二次获取key为peida的数据,缓存已经存在,直接在缓存里面返回
System.out.println("a value:" + cahceBuilder.get("a"));

// 往缓存里面存放数据
cahceBuilder.put("b", "bbbb");
// 缓存已经存在数据了,直接获取
System.out.println("b value:" + cahceBuilder.get("b"));
}

输出结果

请求的key为a在缓存中不存在,通过load方法获取key.
a value:hello a!
a value:hello a!
b value:bbbb

callable callback方式

测试代码

@Test
public void testcallableCache() throws Exception {
Cache<String, String> cache = CacheBuilder.newBuilder().maximumSize(1000).build();
String resultVal = cache.get("a", new Callable<String>() {
public String call() {
String strProValue = "hello " + "a" + "!";
return strProValue;
}
});
System.out.println("a value : " + resultVal);

resultVal = cache.getIfPresent("b");
System.out.println("a value : " + resultVal);
}

输出结果

a value : hello a!
a value : null

cache的参数说明

回收的参数:

  1. 大小的设置:CacheBuilder.maximumSize(long) CacheBuilder.weigher(Weigher) CacheBuilder.maxumumWeigher(long)
  2. 时间:expireAfterAccess(long, TimeUnit) expireAfterWrite(long, TimeUnit)
  3. 引用:CacheBuilder.weakKeys() CacheBuilder.weakValues() CacheBuilder.softValues()
  4. 明确的删除:invalidate(key) invalidateAll(keys) invalidateAll()
  5. 删除监听器:CacheBuilder.removalListener(RemovalListener)
  

refresh机制:

  1. LoadingCache.refresh(K) 在生成新的value的时候,旧的value依然会被使用。
  2. CacheLoader.reload(K, V) 生成新的value过程中允许使用旧的value
  3. CacheBuilder.refreshAfterWrite(long, TimeUnit) 自动刷新cache

guava Cache数据移除

guava做cache时候数据的移除方式,在guava中数据的移除分为被动移除和主动移除两种。
  被动移除数据的方式,guava默认提供了三种方式:
  1.基于大小的移除:看字面意思就知道就是按照缓存的大小来移除,如果即将到达指定的大小,那就会把不常用的键值对从cache中移除。
  定义的方式一般为 CacheBuilder.maximumSize(long),还有一种一种可以算权重的方法,个人认为实际使用中不太用到。就这个常用的来看有几个注意点,
    其一,这个size指的是cache中的条目数,不是内存大小或是其他;
    其二,并不是完全到了指定的size系统才开始移除不常用的数据的,而是接近这个size的时候系统就会开始做移除的动作;
    其三,如果一个键值对已经从缓存中被移除了,你再次请求访问的时候,如果cachebuild是使用cacheloader方式的,那依然还是会从cacheloader中再取一次值,如果这样还没有,就会抛出异常
  2.基于时间的移除:guava提供了两个基于时间移除的方法
    expireAfterAccess(long, TimeUnit) 这个方法是根据某个键值对最后一次访问之后多少时间后移除
    expireAfterWrite(long, TimeUnit) 这个方法是根据某个键值对被创建或值被替换后多少时间移除
  3.基于引用的移除:
  这种移除方式主要是基于java的垃圾回收机制,根据键或者值的引用关系决定移除
  主动移除数据方式,主动移除有三种方法:
  1.单独移除用 Cache.invalidate(key)
  2.批量移除用 Cache.invalidateAll(keys)
  3.移除所有用 Cache.invalidateAll()
  如果需要在移除数据的时候有所动作还可以定义Removal Listener,但是有点需要注意的是默认Removal Listener中的行为是和移除动作同步执行的,如果需要改成异步形式,可以考虑使用RemovalListeners.asynchronous(RemovalListener, Executor)

相关文章