解决Redis的热点缓存问题(双重检查锁)

使用双重检查锁解决热点缓存问题

首先,我们来认识一下什么是热点缓存

我们用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缓存这一步,底层其实做了很多动作:

  1. 申请一个内存缓存空间
  2. 将用户空间中的值读取到内存空间
  3. 赋值,将内存空间中的数据传递给set()方法的形参(内存空间 ----》用户空间)
  4. set()方法会将数据传递到协议引擎ProtocoEngine(用户空间 ----》内存空间)
  5. 协议引擎将数据通过网络传递到redis

在这五步操作中,前面四步是由一个线程完成的,第五步是由一个线程完成的,第五步是将数据存到redis中的。

前面的四步不管顺序再怎么变换,始终不会影响到另外一个线程执行的第五步操作。

当A线程从redis中获取值的时候,redis中是没有数据的,当执行到第四步的时候,这时候B线程进来了,此时redis中是没有值的,因为还没有执行第五步,也不会获取到其他脏数据的

设计模式:https://blog.csdn.net/qq_44890539/article/details/115502250


版权声明:本文为qq_44890539原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。