上一篇文章"Guava Cache特性:对于同一个key,只让一个请求回源load数据,其他线程阻塞等待结果"提到:如果缓存过期,恰好有多个线程读取同一个key的值,那么guava只允许一个线程去加载数据,其余线程阻塞。这虽然可以防止大量请求穿透缓存,但是效率低下。使用refreshAfterWrite可以做到:只阻塞加载数据的线程,其余线程返回旧数据。
package net.aty.guava;
import com.google.common.base.Stopwatch;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class Main {
// 模拟一个需要耗时2s的数据库查询任务
private static Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
System.out.println("begin to mock query db...");
Thread.sleep(2000);
System.out.println("success to mock query db...");
return UUID.randomUUID().toString();
}
};
// 1s后刷新缓存
private static LoadingCache<String, String> cache = CacheBuilder.newBuilder().refreshAfterWrite(1, TimeUnit.SECONDS)
.build(new CacheLoader<String, String>()