Redisson分布式锁快速入门教程

清明在家无事,并且因为上海疫情原因只能宅在家里,突然想到之前计划着写一篇Redisson的分布式锁快速入门教程,自己平常在工作中也只能简单会使用,所以文章可能写的比较简单,希望大佬勿喷。此文章也作为个人的笔记,用于查漏补缺。
补充:目前只是使用Redisson作为分布式锁的用途。

概述

什么是Redisson呢?

Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务。其中包括(BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish / Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service, Scheduler service) Redisson提供了使用Redis的最简单和最便捷的方法。Redisson的宗旨是促进使用者对Redis的关注分离(Separation of Concern),从而让使用者能够将精力更集中地放在处理业务逻辑上。

这是官网对于Redisson的概述。

使用

首先,Redisson对于SpringBoot有对于的整合包,不过我们出于学习目的,先只引入Redisson
Redisson分布式锁快速入门教程_第1张图片


<dependency>
    <groupId>org.redissongroupId>
    <artifactId>redissonartifactId>
    <version>3.17.0version>
dependency>

配置方法

Redisson分布式锁快速入门教程_第2张图片
我们在官方文档中看到有这么多的配置方法,我们先选择使用程序化配置方法进行Redisson的配置。我们可以在右侧Wiki Home里找到第三方框架整合,我们可以选择Spring Cache整合中提供的方式来进行配置

@Configuration
public class MyRedissonConfig {

    @Bean(destroyMethod = "shutdown")
    RedissonClient redisson() throws IOException {
        Config config = new Config();
        // 单Redis节点模式
        config.useSingleServer()
                // 这样配置是有问题的,请先看我下边的解释
                .setAddress("192.168.200.12:6379");
        return Redisson.create(config);
    }
}

如果我们直接这样写,一定会报出**Redis url should start with redis:// or rediss:// (for SSL connection)**这个错误,解决方式是我们需要把192.168.200.12:6379加上redis://rediss://,即redis://192.168.200.12:6379

可重入锁(Reentrant Lock)

	@GetMapping("/hello")
    @ResponseBody
    public String hello() {
        RLock lock = redisson.getLock("anyLock");
        // 最常见的使用方法
        lock.lock();
        System.out.println("获取锁");
        try {
            System.out.println("业务");
            Thread.sleep(15000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            System.out.println("解锁");
            lock.unlock();
        }
        return "hello";
    }

官网简介、redisson中的看门狗机制总结

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

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

	@GetMapping("/hello")
    @ResponseBody
    public String hello() {
        RLock lock = redisson.getLock("anyLock");
        // 更推荐使用明显标注leaseTime的这种方式,可以省去延期锁
        lock.lock(10, TimeUnit.SECONDS);
        System.out.println("获取锁--" + Thread.currentThread().getId());
        try {
            System.out.println("业务--" + Thread.currentThread().getId());
            Thread.sleep(15000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            System.out.println("解锁--" + Thread.currentThread().getId());
            lock.unlock();
        }
        return "hello";
    }

当然,如果我们想设置最长等待时间的话。

	@GetMapping("/hello")
    @ResponseBody
    public String hello() throws InterruptedException {
        RLock lock = redisson.getLock("anyLock");
        // 尝试加锁,最多等待100秒,上锁以后10秒自动解锁
        boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
        if (res) {
            System.out.println("获取锁--" + Thread.currentThread().getId());
            try {
                System.out.println("业务--" + Thread.currentThread().getId());
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("解锁--" + Thread.currentThread().getId());
                lock.unlock();
            }
        }
        return "hello";
    }

读写锁(ReadWriteLock)

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

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

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

    @GetMapping("/read")
    @ResponseBody
    public String readValue() {
        RReadWriteLock rwlock = redisson.getReadWriteLock("anyRWLock");
        // 最常见的使用方法
        RLock rLock = rwlock.readLock();
        // 上锁
        rLock.lock();
        System.out.println("读锁" + Thread.currentThread().getId());

        String uuid = "";
        try {
            uuid = stringRedisTemplate.opsForValue().get("key");
            // 业务
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            System.out.println("解锁" + Thread.currentThread().getId());
            // 解锁
            rLock.unlock();
        }
        return uuid;
    }

    @GetMapping("/write")
    @ResponseBody
    public String writeValue() {
        RReadWriteLock rwlock = redisson.getReadWriteLock("anyRWLock");
        // 最常见的使用方法
        RLock rLock = rwlock.writeLock();
        // 上锁
        rLock.lock();
        System.out.println("写锁" + Thread.currentThread().getId());

        String uuid = "";
        try {
            uuid = UUID.fastUUID().toString();
            stringRedisTemplate.opsForValue().set("key", uuid);
            // 业务
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            System.out.println("解锁" + Thread.currentThread().getId());
            // 解锁
            rLock.unlock();
        }
        return uuid;
    }

信号量(Semaphore)

基于Redis的Redisson的分布式信号量(Semaphore)Java对象RSemaphore采用了与java.util.concurrent.Semaphore相似的接口和用法。

我们拿停车场作为例子,park为停车方法,go为离开停车场方法,当停车场的车位(semaphore)大于0时,可以随便停车,但是当车位(semaphore)等于0时,则park方法会一直阻塞到go方法被激活后停车场的车位(semaphore)大于0

    @GetMapping("/park")
    @ResponseBody
    public String park() throws InterruptedException {
        // 按名称返回信号量实例
        RSemaphore semaphore = redisson.getSemaphore("semaphore");
        // 获得许可。如有必要,等待许可证可用。
        semaphore.acquire();
        return "park";
    }

    @GetMapping("/go")
    @ResponseBody
    public String go() {
        // 按名称返回信号量实例
        RSemaphore semaphore = redisson.getSemaphore("semaphore");
        // 发放许可证。增加可用许可证的数量。
        semaphore.release();
        return "go";
    }

如果我们不想一直让park方法阻塞的话,可以使用以下方式

	@GetMapping("/park")
    @ResponseBody
    public String park() {
        // 按名称返回信号量实例
        RSemaphore semaphore = redisson.getSemaphore("semaphore");
        // 尝试获取当前可用的许可证。
        // 如果获得了许可,则为true ,否则为false
        boolean flag = semaphore.tryAcquire();
        if (flag) {
            // 业务
        } else {
            // 业务
        }
        return "park--" + flag;
    }

闭锁(CountDownLatch)

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

我们可以拿放学这个例子来说明闭锁,当所有的班级全部锁门之后,学校才可以锁门。

    @GetMapping("/lockSchool")
    @ResponseBody
    public String lockSchool() throws InterruptedException {
        // 按名称返回 countDownLatch 实例。
        RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
        // 仅当先前的计数已达到零或根本未设置时才设置新的计数值。
        latch.trySetCount(5);
        // 等到计数器达到零。
        latch.await();
        return "放学啦";
    }

    @GetMapping("/afterSchool")
    @ResponseBody
    public String afterSchool() {
        // 按名称返回 countDownLatch 实例。
        RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
        // 减少锁存器的计数器。当计数达到零时通知所有等待线程。
        latch.countDown();
        return "走了一个班";
    }

你可能感兴趣的:(redis,分布式)