关于缓存失效瞬间,重复构建的思考

68 阅读1分钟

背景需求

读多写少场景,采用先更新数据库后删除缓存的策略

问题聚焦

缓存失效瞬间或数据更新,删除缓存后流量突发,缓存重复构建问题

解决方案

使用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不支持持久化:

PixPin_2024-02-28_17-27-10.png

结论

还得用锁,发现缓存失效,初始化缓存之前,先去获取锁,其他线程获取不到,先自旋一段时间。