结合Redisson分析分布式锁

117 阅读4分钟

1 Redisson 是什么?

Redisson 的宗旨是促进使用者对 Redis 的关注分离(Separation of Concern),从而让使用者能够将精力更集中地放在处理业务逻辑上。

如果你之前已经用 Redis 的话,那使用 Redisson 的话将会事半功倍,Redisson 提供了使用 Redis 的最简单和最便捷的方法。

1.1 redission的基础知识

● Netty 框架:Redisson 采用了基于 NIO 的Netty框架,不仅能作为 Redis 底层驱动客户端,具备提供对 Redis 各种组态形式的连接功能,对 Redis 命令能以同步发送、异步形式发送、异步流形式发送或管道形式发送的功能,LUA脚本执行处理,以及处理返回结果的功能

● 基础数据结构:将原生的 Redis Hash,List,Set,String,Geo,HyperLogLog等数据结构封装为 Java 里大家最熟悉的映射(Map),列表(List),集(Set),通用对象桶(Object Bucket),地理空间对象桶(Geospatial Bucket),基数估计算法(HyperLogLog)等结构;

github.com/redisson/re…

● 分布式数据结构:这基础上还提供了分布式的多值映射(Multimap),本地缓存映射(LocalCachedMap),有序集(SortedSet),计分排序集(ScoredSortedSet),字典排序集(LexSortedSet),列队(Queue),阻塞队列(Blocking Queue),有界阻塞列队(Bounded Blocking Queue),双端队列(Deque),阻塞双端列队(Blocking Deque),阻塞公平列队(Blocking Fair Queue),延迟列队(Delayed Queue),布隆过滤器(Bloom Filter),原子整长形(AtomicLong),原子双精度浮点数(AtomicDouble),BitSet等 Redis 原本没有的分布式数据结构。

github.com/redisson/re…

● 分布式锁:Redisson 还实现了 Redis文档中提到像分布式锁Lock这样的更高阶应用场景。事实上 Redisson 并没有不止步于此,在分布式锁的基础上还提供了联锁(MultiLock),读写锁(ReadWriteLock),公平锁(Fair Lock),红锁(RedLock),信号量(Semaphore),可过期性信号量(PermitExpirableSemaphore)和闭锁(CountDownLatch)这些实际当中对多线程高并发应用至关重要的基本部件。正是通过实现基于 Redis 的高阶应用方案,使 Redisson 成为构建分布式系统的重要工具。

github.com/redisson/re…

这几个部分非常有必要参考官方的wiki!

redission 我们常用其来使用redis分布式锁,但其实它也提供了功能;使我们能更方便的使用redis!

2 整合reddison

2.1 引入依赖

你可以在中央仓库,查询redis依赖

mvnrepository.com/artifact/or…

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

2.2 自定义配置

@Configuration
public class RedissonConfig {
    
    @Bean(destroyMethod="shutdown")
    public Redisson redisson() throws IOException {
        Config config = new Config();
        // 单机模式
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
        // 集群模式
        // config.useClusterServers().addNodeAddress("127.0.0.1:7004", "127.0.0.1:7001");
        return Redisson.create(config);
    }
}

Redisson实际上是 RedissonClient的实现!

我们也可以去看看 redisson-spring-boot-starter 中RedissonAutoConfiguration的配置方式!

如果你不熟悉Redisson,你可以认为其和redisTemplate是一样的;

3 使用案例

如果你对java多线程并发较为熟悉的话,这些api也是极容易理解的!

www.yuque.com/jeffery-zml…

我们当做复习,研究并使用下这些api;

3.1 可重入锁

redisson提供的可重入锁是本次研究的重点;

我们会深入源码去解析之;

1.常用API

image.png 注意waitTime和leaseTime的区别

waitTime 等待加锁的时间

leaseTime 锁持续时长,若没设置,则redission会将其设置为-1,将采用续命锁逻辑

2.使用方式

@Autowire
private Redisson redisson;

public void workWithLock() {
    // 针对业务主键加锁
    RLock lock = redisson.getLock("product:1001:lock");

    lock.lock();
    // 同ReentrantLock,未获取到锁,则会放弃执行机会
    // lock.tryLock(15, TimeUnit.SECONDS);
    // 
    try {
        doWork();
    } catch (Exception e) {

    } finally {
        lock.unlock();
    }
}
@Autowire
private Redisson redisson;

public void workWithTryLock() {
    // 针对业务主键加锁
    RLock lock = redisson.getLock("product:1001:lock");

    try {
        // 同ReentrantLock,未获取到锁,则会放弃执行机会        
        if (!lock.tryLock(15, TimeUnit.SECONDS)) {
            // 若未获得锁,则可以投递至延迟队列,重新等待执行机会
            return;
        }
        doWork();
    } catch (Exception e) {

    } finally {
        lock.unlock();
    }
}

redisson实现的分布式锁,也是和jdk实现的锁是高度一致的;

只要当你理解jdk中高并发工具的使用,才能更好地理解并掌握使用分布式锁!

www.yuque.com/jeffery-zml…

3.2 分布式读写锁

1 使用方式

    public void update() {
        RReadWriteLock readWriteLock = redisson.getReadWriteLock("product:1001:rwlock");
        RLock writeLock = readWriteLock.writeLock();
        writeLock.lock();
        try {
            // 更新时使用写锁
            doUpdateWork();    
        } finally {
            writeLock.unlock();
        }
    }

    public Product get() throws InterruptedException {
        RReadWriteLock readWriteLock = redisson.getReadWriteLock("product:1001:rwlock");
        RLock rLock = readWriteLock.readLock();
        rLock.lock();
        try {
            // 在读场景下,使用读锁
            doGetWork();
        } finally {
            rLock.unlock();
        }
  
        return product;
    }

读写锁,适合读多写锁的业务场景!

请不要在频繁更新场景下,使用读写锁!

时间限制,我们暂时先跳过源码解析!

todo-task

3.3 信号量

3.4 红锁(redLock)

3.5 RedissonLocalCachedMap