使用双重检查锁解决热点缓存问题
首先,我们来认识一下什么是热点缓存
我们用redis来做缓存的时候,都碰到过缓存穿透问题吧,这个就是我要说的热点缓存问题
怎么引起的?
- 就是当我们存在缓存中的数据有一个失效时间,这个时间过期了,在这个期间,有大量的请求访问过来,看redis中没有该数据,会直接去访问MySql数据库,给数据库造成很大的压力
解决
我们来说解决热点缓存的方案:双重检查锁
业务场景:查询学生总人数
//使用双重检查锁
//不存在线程安全问题
@Override
public Integer findUsersCount() {
//获取redis操作对象
BoundValueOperations<Object, Object> ops = redisTemplate.boundValueOps("count");
//从缓存中获取数据
Object count = ops.get();
if(count == null){
synchronized (this){
//再从缓存中获取数据
count = ops.get();
if(count == null){
//从DB中获取数据
count = userMapper.selectCount(null);
//将数据写入缓存 (10秒)
ops.set(count, 10, TimeUnit.SECONDS);
}
}
}
return (Integer) count;
}
大家看我的设计模式这一块,单例模式的懒汉式实现,使用双重检查锁,可能会有线程安全问出现,就是指令重排序问题
思考一下,我们用redis缓存应用双重检查锁会不会也有这个问题呢,其实是不会的
当我们执行添加到redis缓存这一步,底层其实做了很多动作:
- 申请一个内存缓存空间
- 将用户空间中的值读取到内存空间
- 赋值,将内存空间中的数据传递给set()方法的形参(内存空间 ----》用户空间)
- set()方法会将数据传递到协议引擎ProtocoEngine(用户空间 ----》内存空间)
- 协议引擎将数据通过网络传递到redis
在这五步操作中,前面四步是由一个线程完成的,第五步是由一个线程完成的,第五步是将数据存到redis中的。
前面的四步不管顺序再怎么变换,始终不会影响到另外一个线程执行的第五步操作。
当A线程从redis中获取值的时候,redis中是没有数据的,当执行到第四步的时候,这时候B线程进来了,此时redis中是没有值的,因为还没有执行第五步,也不会获取到其他脏数据的
设计模式:https://blog.csdn.net/qq_44890539/article/details/115502250
版权声明:本文为qq_44890539原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。