打造高性能缓存(三)增加缓存过期功能

为每个结果指定过期时间,并定期扫描过期的元素

增加处理缓存过期的方法

 public final static ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);

    public V computer(A arg, long expire) throws ExecutionException, InterruptedException {
        if (expire > 0) {
            executor.schedule(() -> {
                expire(arg);
            }, expire, TimeUnit.SECONDS);
        }
        return computer(arg);
    }

    public synchronized void expire(A key) {
        Future f = cache.get(key);
        if (f != null) {
            if (!f.isDone()) {
                f.cancel(true);
            }
            System.out.println("缓存过期,清除数据");
            cache.remove(key);
        }
    }

测试

public static void main(String[] args) throws Exception {
        TestCache7 expensiveComputer = new TestCache7<>(new MayFail());
        new Thread(() -> {
            try {
                Integer result = expensiveComputer.computer("666", 5L);
                System.out.println("第一次计算结果:" + result + ",时间:" + System.currentTimeMillis());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();

        new Thread(() -> {
            try {
                Integer result = expensiveComputer.computer("666", 5L);
                System.out.println("第二次计算结果:" + result + ",时间:" + System.currentTimeMillis());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
        Thread.sleep(6000L);
        new Thread(() -> {
            try {
                Integer result = expensiveComputer.computer("666", 5L);
                System.out.println("第三次计算结果:" + result + ",时间:" + System.currentTimeMillis());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    }

结果

从FutureTask调用了计算逻辑
第二次计算结果:666,时间:1660618173243
第一次计算结果:666,时间:1660618173243
缓存过期,清除数据
从FutureTask调用了计算逻辑
第三次计算结果:666,时间:1660618179252
缓存过期,清除数据

从结果可以看到前两次的计算结果是正常的,而当5s时间以后,缓存被清除,第三次的计算就重新进行了数据的计算

高并发下的缓存问题

如果大量的缓存同时过期,那么同时都拿不到缓存,在高并发的情况下,导致大量的请求打爆cpu和数据库,就会造成缓存雪崩、缓存击穿等高并发下的缓存问题。所以我们可以把缓存的过期时间设置为随机

包装computer(A arg, long expire)

    public V computerRandomExpire(A arg) throws ExecutionException, InterruptedException {
        long randomExpire = (long) (Math.random() * 10000);// 根据实际业务需要设置一个缓存范围。
        return computer(arg, randomExpire);
    }

这样每个缓存的过期时间都是随机的,尽可能的避免大量缓存同时过期的情况出现,保障系统的安全

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注