Redisson框架
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. 锁续期
- 当用户没有指定锁的超时时间的时候,那么此时Redisson框架会自动给锁进行续期。
- 续期规则:当锁的过期时间到达设置时间的1/3的时候,会自动续期到默认的30s
- 续期原理:通过一个定时任务(异步线程)进行实现
- 当业务产生异常,锁没有释放,watch dog会不断地给锁续期,所以释放锁的操作一定要放到finally中
- watch dog机制启动,且代码中没有释放锁的操作时,watch dog会不断的给锁续期
- watch dog的延时时间可以自由指定:
config.setLockWatchdogTimeout(6000)
- 源码调用过程:
RedissonLock #tryLock ----> tryLockAsync ----> tryLockAsync ----> tryAcquireOnceAsync ----> scheduleExpirationRenewal ----> renewExpiration
6. 释放锁代码需要写在finally语句中,否则业务代码产生异常以后,给锁续期的线程还是会继续执行,最终造成死锁。原因:给锁续期的线程是一个异步线程,主线程异常不影响异步线程的执行。
释放锁操作异常,watch dog还会不停的续期吗?
不会,因为无论释放锁操作是否成功,EXPIRATION_RENEWAL_MAP中的目标 ExpirationEntry 对象已经被移除了,watch dog 通过判断后就不会继续给锁续期了。
7. 加解锁必须成对出现
- 通过如下方式获取的锁是可重入锁:
RLock lock = redissonClient.getLock("redisson-lock");
- 可重入锁实现原理:对hash结构中的value值进行加1操作
- 可重入锁:获取锁的线程在执行一个需要锁的方法的时候(前提:锁对象是同一个对象),是否需要重新获取锁。如果需要重新获取,那么这个锁就不是可重入锁,如果不需要就是可重入锁。
- 可重入锁有哪些: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() ;
}
作者:摆烂ing
出处:http://www.cnblogs.com/insilently/
版权:本文版权归作者所有
转载:欢迎转载,但未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必追究法律责任
出处:http://www.cnblogs.com/insilently/
版权:本文版权归作者所有
转载:欢迎转载,但未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必追究法律责任