背景需求
读多写少场景,采用先更新数据库后删除缓存的策略
问题聚焦
缓存失效瞬间或数据更新,删除缓存后流量突发,缓存重复构建问题
解决方案
使用future,利用get方法的阻塞功能实现
public class Main {
private final Map<String, CompletableFuture<String>> CACHE = new ConcurrentHashMap<>();
public String query(String key) throws Exception {
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 2
, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1));
CompletableFuture<String> future = CACHE.get(key);
if (future == null) {
CompletableFuture<String> thisTask = CompletableFuture.supplyAsync(() -> "查询数据库~~", executor);
future = CACHE.putIfAbsent(key, thisTask);
if (future == null) {
future = thisTask;
thisTask.run();
}
}
return future.get();
}
}
发散
貌似只对单机情况有效,分布式场景有问题,想是否可以把future放到redis中? 如下:
public class Main {
public static void main(String []args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 2
, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1));
CompletableFuture<String> futureTask = CompletableFuture.supplyAsync(() -> "success", executor);
redisService.setObject("futureTask",futureTask);
String result = futureTask.get();
log.info(result);
CompletableFuture<String> redisResult = (CompletableFuture<String>) redisService.getObject("futureTask");
log.info(result);
}
}
运行发现,future不支持持久化:
结论
还得用锁,发现缓存失效,初始化缓存之前,先去获取锁,其他线程获取不到,先自旋一段时间。