zoukankan      html  css  js  c++  java
  • 分布式锁

    1、加锁解决缓存击穿问题

    1)本地锁: 使用同步代码块

    public Map<String,List<Catalog2Vo>> getCatalogJsonFromDb() {
        //只要是同一把锁,就能锁住使用这个锁的所有线程
        //synchronized (this)  SpringBoot项目中所有组件在容器中都是单例的
        synchronized (this){
            //得到锁之后,需要去缓存中查询一次,如果没有,才继续查询数据库
            String result = redisTemplate.opsForValue().get("xxxx");
            if(StringUtils.isNotBlank(result )){
                return result;
            }
           //查询数据库,返回结果
           return getResuleFromDb();
        }
    }

    2)本地锁在分部式情况下出现的问题

    每个本地锁只能锁住当前项目请求过来的10000个请求,多个项目的情况下,依旧会查询多次数据库

    0

    2、分布式锁的原理和使用

    1)分布式锁出现的问题

    死锁:setnx占好了位,业务代码异常或者程序在页面过程中宕机,没有执行删除逻辑,这就造成了死锁问题

    解决:设置锁的自动过期,即使没有删除也会自动删除

    3、Redisson的使用

    整合Redisson作为分布式锁

    1)引入依赖

    <dependency>
        <groupId>org.redisson</groupId>
        <artifactId>redisson</artifactId>
        <version>3.12.0</version>
    </dependency>

    2)配置

    /**
     * @author houChen
     * @date 2021/10/31 9:37
     * @Description: Redisson的配置类
     */
    @Configuration
    public class MyRedissonConfig {
        /**
         *  所有对Redisson的使用都是通过RedissonClient对象
         */
        @Bean
        public RedissonClient redisson(){
            //1、创建配置
            Config config = new Config();
            config.useSingleServer().setAddress("121.40.182.123:6379");
            //2、创建RedissonClient
            return Redisson.create(config);
        }
    }

    3)测试

    mylock.lock() 是阻塞式的,若某个请求没有获取到锁,则一直阻塞在该处。

    @ResponseBody
    @GetMapping("/hello")
    public String hello(){
        //1、获取一把锁,只要锁名一样,就是同一把锁
        RLock mylock = redisson.getLock("mylock");
        //2、加锁
        mylock.lock();
        try{
            System.out.println("加锁成功,正在执行业务......"+ Thread.currentThread().getId());
            Thread.sleep(30000);
        }catch (Exception e){
    
        }finally {
            System.out.println("释放锁" + Thread.currentThread().getId());
            mylock.unlock();
        }
        return  "hello";
    }

    0

    4)一些问题

    当加锁后,程序闪退了,没有执行解锁代码,会不会造成死锁?

    不会,因为当锁没有续期时,超过30秒回自动删除

    1)锁的自动续期,如果业务超长,运行期间会自动给锁续上30秒。不用担心业务时间长,锁自动过期被删除

    2)加锁的业务只要运行完成,就不会给当前锁续期,即使不手动解锁,锁默认在30秒后自动删除

    mylock.lock(10, TimeUnit.SECONDS); 10秒后会自动解锁,但是不会续期,所以解锁的时间一定要大于业务执行的时间

    1、如果我们传递了锁的超时时间,就发送指令给redis脚本,进行占锁,默认超时就是我们指定的时间

    2、如果我们未指定锁的超时时间,就使用30*1000 【LockWatchOutTimeOut看门狗的默认时间】

    只要占领成功,就会启动一个定时任务【重新给锁设置过期时间,新的过期时间就是看门狗的默认时间】,每隔10秒自动 续期

    4、Redisson 读写锁

    5、Redisson 闭锁

    /**
     *  闭锁演示
     *
     *  5个班的人都走完了,才能锁大门
     */
    @GetMapping("/lockDoor")
    @ResponseBody
    public String lockDoor() throws InterruptedException {
        RCountDownLatch door = redisson.getCountDownLatch("door");
        door.trySetCount(5);
        door.await(); //等待闭锁都完成
        return  "放假了";
    }
    
    @GetMapping
    @ResponseBody
    public String gogogo(@PathVariable("id") Long id){
        RCountDownLatch door = redisson.getCountDownLatch("door");
        door.countDown(); // 计数减1
        return id + "班的人走了";
    }

    0

    6、Redisson 分布式信号量

    /**
     * 分布式信号量测试
     * 车位停车   3车位
       当车位为0时,停车操作将会阻塞
     *
     * 可以用来做分布式限流
     */
    @GetMapping("/park")
    @ResponseBody
    public String park() throws InterruptedException {
        RSemaphore park = redisson.getSemaphore("park");
        park.acquire();  //获取一个信号(占一个车位)
        return "ok";
    }
    
    @GetMapping("/go")
    @ResponseBody
    public String go() throws InterruptedException {
        RSemaphore park = redisson.getSemaphore("park");
        park.release();  //获取一个信号
        return "go 车开走啦....";
    }
  • 相关阅读:
    安卓学习-其他-网络状态工具
    安卓学习-界面-ui-Notification
    安卓学习-界面-ui-ScrollView和HorizontalScrollView
    安卓学习-界面-ui-TabHost
    安卓学习-界面-ui-SearchView
    OpecnCV训练分类器详细整理
    OopenCV复习及函数深入理解(轮廓查询及绘图)
    ASP.NET基础学习未整理随笔
    C#或ASP.NET绘图初探
    ASP.NET基础学习(暴力破解密码)
  • 原文地址:https://www.cnblogs.com/houchen/p/15616649.html
Copyright © 2011-2022 走看看