• redis的分布式锁框架redisson之体验分布式锁


    使用

    1、引入依赖:

    <!--以后使用redis作为所有分布式锁,分布式对象等功能框架-->
    <!-- https://mvnrepository.com/artifact/org.redisson/redisson -->
    <dependency>
        <groupId>org.redisson</groupId>
        <artifactId>redisson</artifactId>
        <version>3.12.0</version>
    </dependency>

    2、程序化配置方法

    @Configuration
    public class MyRedisConfig {
    
        @Bean(destroyMethod="shutdown")
        public RedissonClient redisson() throws IOException {
            Config config = new Config();
            config.useSingleServer().setAddress("redis://127.0.0.1:6379").setPassword("li199852");
            RedissonClient redisson = Redisson.create(config);
            return redisson;
        }
    }

    以后操作都是使用redissonClient操作:

    @Autowired
    RedissonClient redissonClient;

    4、可重入锁(Reentrant Lock)

    他的使用和java的Lack锁差不多:

    @GetMapping("/hello")
    @ResponseBody
    public String hello(){
        //1.获取一把锁,只要锁的名字一样,就是同一把锁
        RLock lock = redisson.getLock("my-lock");
        //2.加锁
        lock.lock();//原理是阻塞式等待,默认加的锁都是30s的时间
        /*
        问题:lock.lock(10, TimeUnit.SECONDS)锁到期之后,不会自动续期。
            1、如果我们传递了锁的超时时间,就发送给redis执行脚本,进行占锁,默认超时就是我们指定的时间
            2、如果我们未指定锁的超时时间,就使用30*1000【lockWatchdogTimeout看门狗的默认时间】;
                只要占锁成功,就会启动一个定时任务【重新给锁设置过期时间,新的过期时间就是看门狗的默认时间】
                initernallockLeaseTime【看门狗时间】 / 3 ,也就是10秒调用一次重置时间方法
    
        */
        /*
        优点:
            1)、锁的自动续期,如果业务超长,运行期间自动给锁锁上新的30s。不用担心业务时间长,锁自动被删掉
            2)、加锁的业务自动运行完成,就不会给当前锁续期,即使不手动解锁,锁默认会在30s以后自动删除
        */
        try {
            System.out.println("我拿到了锁"+Thread.currentThread().getId());
                Thread.sleep(20000);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //3.解锁,假设解锁代码没有运行,redisson会不会出现死锁:不会,锁默认会在30s以后自动删除
            System.out.println("我释放了锁"+Thread.currentThread().getId());
            lock.unlock();
        }
        return "hello";
    }

     推荐使用:

      可以省掉续期的操作,如果业务30秒还执行不完,就要改造业务了;

    lock.lock(30, TimeUnit.SECONDS);//锁到期之后,不会自动续期,需要手动解锁。

    5、读写锁(ReadWriteLock)

        //保证一定能读到最新数据,修改期间,写锁是一个排他锁(互斥锁)。
        //读锁是一个共享锁写锁没释放读就必须等待
        /*
        先读 + 后读:相当于无锁,并发读,只会在redis中记录好,所有当前的读锁。他们都会同时加锁成功
        先写 + 后读:等待写锁释放
        先写 + 后写:阻塞方式
        先读 + 后写:有读锁。写也需要等待。
        只要有写的存在,都必须等待
         */
        @RequestMapping("/write")
        @ResponseBody
        public String writeString() {
            RReadWriteLock readWriteLock = redisson.getReadWriteLock("readWriteLock");
            RLock wLock = readWriteLock.writeLock();
            String s = "";
            try {
                wLock.lock(20, TimeUnit.SECONDS);
                s = UUID.randomUUID().toString();
                Thread.sleep(10000);
                redisTemplate.opsForValue().set("s", s);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                wLock.unlock();
            }
            return s;
        }
    
        @RequestMapping("/read")
        @ResponseBody
        public String readString() {
            RReadWriteLock readWriteLock = redisson.getReadWriteLock("readWriteLock");
            RLock rLock = readWriteLock.readLock();
            String s = "";
            try {
                rLock.lock(20,TimeUnit.SECONDS);
                s =  redisTemplate.opsForValue().get("s");
            }finally {
                rLock.unlock();
            }
    
            return s;
        }

    6、信号量(Semaphore)(还有一个可过期性信号量(PermitExpirableSemaphore))

        /**
    * 信号量(Semaphore)
    * 默认是获取的
    * @return
    */
    @RequestMapping("/goOneCar")
    @ResponseBody
    public String goOneCar(){
    RSemaphore semaphore = redisson.getSemaphore("semaphore-Lock");
    semaphore.release();//释放当前一个车位
    return "出去一辆车";
    }

    @RequestMapping("/comeOneCar")
    @ResponseBody
    public String comeOneCar() throws InterruptedException {
    RSemaphore semaphore = redisson.getSemaphore("semaphore-Lock");
    // semaphore.acquire();//获取当前一个车位
    semaphore.tryAcquire(10);//尝试获取当前十个车位,没有或不够就算了
    return "进来一辆车";
    }

    7、闭锁(CountDownLatch)

        /**
         * 闭锁:CountDownLatch
         * 五个人都走出教室了在锁门,
         */
        //锁门
        @RequestMapping("/closeDoor")
        @ResponseBody
        public String closeDoor() throws InterruptedException {
            RCountDownLatch countDownLatch = redisson.getCountDownLatch("countDownLatch-Lack");
            countDownLatch.trySetCount(5);
            countDownLatch.await();
            return "门锁了";
        }
    
        //出去
        @RequestMapping("/goOut")
        @ResponseBody
        public String goOut(Long id){
            RCountDownLatch countDownLatch = redisson.getCountDownLatch("countDownLatch-Lack");
            countDownLatch.countDown();
            return id+"出去了";
        }

    其他可以参考redis官网,链接:https://github.com/redisson/redisson/wiki/8.-%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81%E5%92%8C%E5%90%8C%E6%AD%A5%E5%99%A8

  • 相关阅读:
    写了一个自动打包并发布到tomcat的脚本
    查看并更改mysql编码
    MyBatis无法根据中文条件查询出结果
    服务器端PHP多进程编程
    PHP-popen()&nbsp;函数打开进程文件指针
    php并发处理
    PHP能得到你是从什么页面过来的,r…
    PHP如何解决网站大流量与高并发的…
    基于PHP的cURL快速入门
    Mysql内存表的用处
  • 原文地址:https://www.cnblogs.com/lzghyh/p/13267880.html
Copyright © 2020-2023  润新知