Redisson框架

发布时间 2023-08-14 00:06:05作者: 摆烂ing

1. Redisson简介

Redisson:是一个高级的分布式协调Redis客服端 , 专注于分布式系统开发,让用户可以在分布式系统中很方便的去使用Redis

2. 环境搭建

2.1 加入依赖

<!-- redisson 分布式锁-->
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.17.7</version>
</dependency>

2.2 定义配置类

@Configuration
public class RedissonConfiguration {

    @Autowired
    private RedisProperties redisProperties;

    @Bean
    public RedissonClient redissonClient(){
        Config config = new Config();
        config.useSingleServer().setAddress("redis://" + redisProperties.getHost() + ":" + redisProperties.getPort())
                .setPassword(redisProperties.getPassword());
        RedissonClient redissonClient = Redisson.create(config);
        return redissonClient;
    }
}

3. RedissonClient常见的加锁方法

// 获取RedissonClient锁对象
RLock lock = redissonClient.getLock("redisson-lock");
// 一直等待获取锁,直到获取到锁为止! 默认锁的存活时间为30s
lock.lock();
// 一直等待获取锁,并且显式的指定锁的过期时间
lock.lock(10 , TimeUnit.SECONDS);
// 尝试获取一次锁,如果可以获取到锁就返回true,否则返回false,默认情况下锁的过期时间为30s
lock.tryLock();
// 尝试获取一次锁,指定加锁的等待超时时间为3s, 如果在3s内获取到了锁,那么此时就返回true,否则返回false, 默认情况下锁的过期时间为30s
boolean tryLock = lock.tryLock(3, 20, TimeUnit.SECONDS);

4. Redisson框架使用lua脚本保证加锁和设置锁的过期时间原子性

源码调用过程:
RedissonLock #tryLock ----> tryAcquire ----> tryAcquireAsync ----> tryLockInnerAsync

5. 锁续期

  1. 当用户没有指定锁的超时时间的时候,那么此时Redisson框架会自动给锁进行续期。
  2. 续期规则:当锁的过期时间到达设置时间的1/3的时候,会自动续期到默认的30s
  3. 续期原理:通过一个定时任务(异步线程)进行实现
  4. 当业务产生异常,锁没有释放,watch dog会不断地给锁续期,所以释放锁的操作一定要放到finally中
  5. watch dog机制启动,且代码中没有释放锁的操作时,watch dog会不断的给锁续期
  6. watch dog的延时时间可以自由指定:config.setLockWatchdogTimeout(6000)
  7. 源码调用过程:
    RedissonLock #tryLock ----> tryLockAsync ----> tryLockAsync ----> tryAcquireOnceAsync ----> scheduleExpirationRenewal ----> renewExpiration

6. 释放锁代码需要写在finally语句中,否则业务代码产生异常以后,给锁续期的线程还是会继续执行,最终造成死锁。原因:给锁续期的线程是一个异步线程,主线程异常不影响异步线程的执行。

释放锁操作异常,watch dog还会不停的续期吗?
不会,因为无论释放锁操作是否成功,EXPIRATION_RENEWAL_MAP中的目标 ExpirationEntry 对象已经被移除了,watch dog 通过判断后就不会继续给锁续期了。

7. 加解锁必须成对出现

  1. 通过如下方式获取的锁是可重入锁:RLock lock = redissonClient.getLock("redisson-lock");
  2. 可重入锁实现原理:对hash结构中的value值进行加1操作
  3. 可重入锁:获取锁的线程在执行一个需要锁的方法的时候(前提:锁对象是同一个对象),是否需要重新获取锁。如果需要重新获取,那么这个锁就不是可重入锁,如果不需要就是可重入锁。
  4. 可重入锁有哪些:synchronized,ReentrantLock

8. 其它锁介绍

8.1 公平锁

获取锁的顺序和线程的等待顺序一致
RLock lock = redissonClient.getFairLock("myLock");

8.2 读写锁

RReadWriteLock rwlock = redissonClient.getReadWriteLock("myLock");
读写锁特性:读读兼容、读写互斥、写写互斥、写读互斥
获取读锁:

RLock readLock = readWriteLock.readLock();
readLock.lock();
readLock.unlock();

获取写锁:

RLock writeLock = readWriteLock.writeLock();
writeLock.lock();
writeLock.unlock();

9. 信号量

9.1 作用

让某一段代码被指定个线程执行,即限流

9.2 使用

RSemaphore semaphore = null;  // 定义一个信号量对象

@PostConstruct
public void init() {
    semaphore = redissonClient.getSemaphore("test-semaphore");
    semaphore.addPermits(2);
}

@GetMapping(value = "/semaphore")
public Result semaphore() throws InterruptedException {
    semaphore.acquire();  // 申请凭证
    log.info(Thread.currentThread().getName() + "----> 申请到了一个凭证...");
    Thread.sleep(500);
    semaphore.release();
    log.info(Thread.currentThread().getName() + "----> 归还了一个凭证....");
    return Result.ok() ;
}