打造高性能缓存(三)增加缓存过期功能
最后更新于:2022-08-16 11:02:24
为每个结果指定过期时间,并定期扫描过期的元素
增加处理缓存过期的方法
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);
}
这样每个缓存的过期时间都是随机的,尽可能的避免大量缓存同时过期的情况出现,保障系统的安全