谷粒商城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还是很有用的,等后面扩大了服务器的内存,在加入一下。

 

posted @ 2020-06-24 14:31  天宇轩-王  阅读(855)  评论(0编辑  收藏  举报