zoukankan      html  css  js  c++  java
  • 谷粒商城Redisson分布式锁(二十四)

     159、缓存-分布式锁-Redisson简介&整合 - 166、缓存-分布式锁-缓存一致性解决

     官网说明:https://github.com/redisson/redisson

     反正也很详细,有说明,也有配置的用法,感兴趣的可以具体看一下。底层也是用到lua脚本

        /**
         * 简单请求
         * @return
         */
        @ResponseBody
        @GetMapping("/hello")
        public String hello() {
            RLock rLock = redisson.getLock("my-lock");
            //1.锁的自动续期,如果业务超长,运行期间会自动给锁续上新的30s。不用担心业务时间长,锁自动被删掉
            //2.加锁的业务只要运行完成,就不会给当前锁续期,即使不手动解锁,锁默认在30s以后自动删除。
            //rLock.lock();
            rLock.lock(30, TimeUnit.SECONDS);  //10秒自动解锁,自动解锁时间一定要大于业务的执行时间
            //问题:rLock.lock(10, TimeUnit.SECONDS);  在锁时间到了以后,不会自动续期
            //1.如果我们传递了锁的超时时间,就发送给redis执行脚本,进行占锁,默认超时就是我们指定的时间。
            //2.如果我们未指定锁的超时时间,就使用30*1000的LockWatchTimeout看门狗的默认时间;
            // 只要占锁成功,就会启动一个定时任务,每隔10s都会自动续期
            //建议; rLock.lock(30, TimeUnit.SECONDS); 省掉了续期的时间
            try {
                System.out.println("加锁成功,执行业务"+Thread.currentThread().getId());
                Thread.sleep(30000);
            }catch(Exception e){
    
            }finally {
                System.out.println("释放锁"+Thread.currentThread().getId());
                rLock.unlock();
            }
    
            

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

    读写锁(ReadWriteLock)

    基于Redis的Redisson分布式可重入读写锁RReadWriteLock Java对象实现了java.util.concurrent.locks.ReadWriteLock接口。其中读锁和写锁都继承了RLock接口。

    分布式可重入读写锁允许同时有多个读锁和一个写锁处于加锁状态。

    RReadWriteLock rwlock = redisson.getReadWriteLock("anyRWLock");
    // 最常见的使用方法
    rwlock.readLock().lock();
    //
    rwlock.writeLock().lock();

    大家都知道,如果负责储存这个分布式锁的Redis节点宕机以后,而且这个锁正好处于锁住的状态时,这个锁会出现锁死的状态。为了避免这种情况的发生,Redisson内部提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期。默认情况下,看门狗的检查锁的超时时间是30秒钟,也可以通过修改Config.lockWatchdogTimeout来另行指定。

    另外Redisson还通过加锁的方法提供了leaseTime的参数来指定加锁的时间。超过这个时间后锁便自动解开了。

    // 10秒钟以后自动解锁
    // 无需调用unlock方法手动解锁
    rwlock.readLock().lock(10, TimeUnit.SECONDS);
    //
    rwlock.writeLock().lock(10, TimeUnit.SECONDS);
    
    // 尝试加锁,最多等待100秒,上锁以后10秒自动解锁
    boolean res = rwlock.readLock().tryLock(100, 10, TimeUnit.SECONDS);
    //
    boolean res = rwlock.writeLock().tryLock(100, 10, TimeUnit.SECONDS);
    ...
    lock.unlock();

    闭锁(CountDownLatch)

    基于Redisson的Redisson分布式闭锁(CountDownLatch)Java对象RCountDownLatch采用了与java.util.concurrent.CountDownLatch相似的接口和用法。

    RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
    latch.trySetCount(1);
    latch.await();
    
    // 在其他线程或其他JVM里
    RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
    latch.countDown();
        @GetMapping("/lockDoor")
        @ResponseBody
        public  String lockDoor () throws InterruptedException {
            RCountDownLatch door = redisson.getCountDownLatch("door");
            door.trySetCount(5);
            door.await();
            return "放假了。。。";
        }
    
        @GetMapping("/gogogo/{id}")
        @ResponseBody
        public String gogogo(@PathVariable("id") Long id){
            RCountDownLatch door = redisson.getCountDownLatch("door");
            door.countDown();
            return id+"班的人都走了";
        }

    信号量(Semaphore)

    基于Redis的Redisson的分布式信号量(Semaphore)Java对象RSemaphore采用了与java.util.concurrent.Semaphore相似的接口和用法。同时还提供了异步(Async)、反射式(Reactive)和RxJava2标准的接口。

    RSemaphore semaphore = redisson.getSemaphore("semaphore");
    semaphore.acquire();
    //
    semaphore.acquireAsync();
    semaphore.acquire(23);
    semaphore.tryAcquire();
    //
    semaphore.tryAcquireAsync();
    semaphore.tryAcquire(23, TimeUnit.SECONDS);
    //
    semaphore.tryAcquireAsync(23, TimeUnit.SECONDS);
    semaphore.release(10);
    semaphore.release();
    //
    semaphore.releaseAsync();

     加上Redisson锁

        //Redisson加上分布式锁
        public Map<String, List<Catalog2Vo>> getCatalogJsonFromDbRedissonLock() {
            RLock lock = redisson.getLock("catalogSon-lock");
            lock.lock();
            log.info("分布式加锁成功");
            Map<String, List<Catalog2Vo>> dataFromDb;
            try{
                dataFromDb = getDataFromDb();
            }finally{
                lock.unlock();
                log.info("分布式解锁成功");
            }
            return dataFromDb;
        }

     解决方案:

     

     

     canal还是很有用的,等后面扩大了服务器的内存,在加入一下。

  • 相关阅读:
    [Real World Haskell翻译]第24章 并发和多核编程 第一部分并发编程
    [Real World Haskell翻译]第22章 扩展示例:Web客户端编程
    [Real World Haskell翻译]第27章 网络通信和系统日志 Sockets and Syslog
    druid 解密
    git clone 所有远程分支到本地
    十、Delphi 把Json转成Delphi实体类
    XML External Entity attack/XXE攻击
    大家好!
    XXE攻防——XML外部实体注入
    ubuntu安装Go环境
  • 原文地址:https://www.cnblogs.com/dalianpai/p/13183672.html
Copyright © 2011-2022 走看看