分布式锁 Redisson
依赖
<!-- redisson 分布式锁-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.11.6</version>
</dependency>
配置
@Configuration
public class RedissonConfig {
@Bean
public RedissonClient getRedisson(){
Config config = new Config();
//单机模式 依次设置redis地址和密码
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
config.setCodec(new StringCodec());
return Redisson.create(config);
}
}
测试
@Test
public void testRedssion() throws InterruptedException {
RLock rlock = redissonClient.getLock("anyLock");
/**
* 获取锁最大等待时间(失败会重试)
* 锁释放时间
* 单位
*
*/
boolean tryLock = rlock.tryLock(1, 10, TimeUnit.SECONDS);
try {
if (tryLock) {
System.out.println("执行业务逻辑");
}
} finally {
rlock.unlock();
}
}
可重入锁
在一个线程内可以多次获取同一把锁
- Redisson通过锁计数实现,同一个线程加锁时,锁计数+1
- 同一个线程释放锁时,锁计数-1,锁为0时才释放锁
- 为了保证多条命令的原子性,必须采取lua脚本来做
锁重试机制
利用信号量和pubsub(消费订阅)实现等待和唤醒,获取锁失败的重试机制
@Test
public void Relock() throws InterruptedException {
RLock rlock = redissonClient.getLock("anyLock");
/**
* 获取锁最大等待时间(失败会重试)
* 锁释放时间
* 单位
*/
// 设置重试时间10S
boolean tryLock = rlock.tryLock(10L, 60L, TimeUnit.SECONDS);
try {
if (tryLock) {
System.out.println("执行业务逻辑");
}
} finally {
rlock.unlock();
}
}
超时续约
- leaseTime为-1 开启续约机制
利用watchDog机制(看门狗),每隔一段时间(ReleaseTime / 3), 重置超时时间
/**
* 获取锁最大等待时间(失败会重试)
* 锁释放时间(-1、默认开启续约watchDog)
* 单位
*/
//boolean tryLock = rlock.tryLock(10L, TimeUnit.SECONDS);// 默认leaseTime=-1
boolean tryLock = rlock.tryLock(10L, -1L, TimeUnit.SECONDS);
try {
if (tryLock) {
System.out.println("执行业务逻辑");
}
} finally {
rlock.unlock();
}
联锁机制
解决单台redis宕机,导致的锁失效问题
- redis高可用时,保证锁的一致性,原理:尝试对获取每一台redis锁,全部获取到则加锁成功
配置多台redis
@Configuration
public class RedissonConfig {
@Bean
@Primary
public RedissonClient redissonClient(){
Config config = new Config();
//单机模式 依次设置redis地址和密码
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
return Redisson.create(config);
}
@Bean
public RedissonClient redissonClient1(){
Config config = new Config();
//单机模式 依次设置redis地址和密码
config.useSingleServer().setAddress("redis://127.0.0.1:6374").setPassword("123456");
return Redisson.create(config);
}
}
将所有锁联合成一个RedissonMultiLock
@Resource
RedissonClient redissonClient1;
@Resource
RedissonClient redissonClient2;
@Test
public void mLock() throws InterruptedException {
RLock lock1 = redissonClient1.getLock("anyLock");
RLock lock2 = redissonClient2.getLock("anyLock");
RLock multiLock = redissonClient1.getMultiLock(lock1, lock2);
boolean tryLock = multiLock.tryLock(5L, TimeUnit.SECONDS);
try {
if (tryLock) {
System.out.println("执行业务逻辑");
}
} finally {
multiLock.unlock();
}
}