文章目录
- 分布式锁
- 不可重入Redis分布式锁
- Redisson
- 快速入门
- 可重入的Redis分布式锁
- Redisson的multiLock
分布式锁
分布式锁:满足分布式系统或集群模式下多进程可见并且互斥的锁。
分布式锁的核心是实现多进程之间互斥,而满足这一点的方式有很多,常见的有三种:
不可重入Redis分布式锁
原理:利用setnx的互斥性;利用ex避免死锁;释放锁时判断线程标示 缺陷:不可重入、无法重试、锁超时失效
实现分布式锁时需要实现的两个基本方法:
- 获取锁:
- 互斥:确保只能有一个线程获取锁
- 添加锁,利用setnx的互斥特性
- 添加锁过期时间,避免服务宕机引起的死锁
- 释放锁
- 手动释放
- 超时释放:获取锁时添加一个超时时间
# 释放锁,删除即可
DEL key
分布式锁实现,满足:
在获取锁时存入线程标示(可以用UUID表示)
在释放锁时先获取锁中的线程标示,判断是否与当前线程标示一致
如果一致则释放锁
如果不一致则不释放锁
Redisson
https://github.com/redisson/redisson
快速入门
可重入的Redis分布式锁
原理:利用hash结构,记录线程标示和重入次数;利用watchDog延续锁时间;利用信号量控制锁重试等待
缺陷:redis宕机引起锁失效问题
依赖
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.13.6</version>
</dependency>
配置Redisson客户端:
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RedisConfig {
@Bean
public RedissonClient redisClient() {
Config config = new Config();
config.useSingleServer().setAddress("redis://47.96.16.107:6379").setPassword("654321");
return Redisson.create(config);
}
}
使用
@Resource
private RedissonClient redissonClient;
@Test
void testRedisson() throws InterruptedException {
// 获取锁(可重入),指定锁的名称
RLock lock = redissonClient.getLock("anyLock");
// 尝试获取锁,参数分别是:获取锁的最大等待时间(期间会重试),锁自动释放时间,时间单位
boolean isLock = lock.tryLock(1, 10, TimeUnit.SECONDS);
// 判断释放获取成功
if (isLock) {
try {
System.out.println("执行业务");
} finally {
// 释放锁
lock.unlock();
}
}
}
Redisson的multiLock
配置类
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RedisConfig {
@Bean
public RedissonClient redisClient1() {
Config config = new Config();
config.useSingleServer().setAddress("redis://47.96.16.107:6379").setPassword("654321");
return Redisson.create(config);
}
@Bean
public RedissonClient redisClient2() {
Config config = new Config();
config.useSingleServer().setAddress("redis://47.96.16.107:6380").setPassword("654321");
return Redisson.create(config);
}
@Bean
public RedissonClient redisClient3() {
Config config = new Config();
config.useSingleServer().setAddress("redis://47.96.16.107:6381").setPassword("654321");
return Redisson.create(config);
}
}
multiLock
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
@Slf4j
@SpringBootTest
class SimpleLockTest {
@Resource
private RedissonClient redissonClient1;
@Resource
private RedissonClient redissonClient2;
@Resource
private RedissonClient redissonClient3;
@Test
void testRedisson() throws InterruptedException {
RLock lock1 = redissonClient1.getLock("apple");
RLock lock2 = redissonClient2.getLock("apple");
RLock lock3 = redissonClient3.getLock("apple");
RLock lock = redissonClient1.getMultiLock(lock1, lock2, lock3);
// // 获取锁(可重入),指定锁的名称
// RLock lock = redissonClient.getLock("anyLock");
// 尝试获取锁,参数分别是:获取锁的最大等待时间(期间会重试),锁自动释放时间,时间单位
boolean isLock = lock.tryLock(1, 10, TimeUnit.SECONDS);
// 判断释放获取成功
if (isLock) {
try {
System.out.println("执行业务");
} finally {
// 释放锁
lock.unlock();
}
}
}