在单节点服务中,我们可以使用
synchronized
来保证同一时间内只允许一个线程执行限定的代码块。但是如果我们是多节点服务呢,因为synchronized
是针对服务内部的,其他服务是无法受到他的干预的。那么如何保证多个节点在同一时间内只允许一个节点中的一个线程去访问这个代码块呢?使用
分布式锁
!!!本文使用
Redisson
来操作Redis
并实现分布式锁
官网:https://github.com/redisson/redisson/tree/redisson-3.16.8
引入依赖
<dependency>
<groupId>org.redissongroupId>
<artifactId>redissonartifactId>
<version>3.16.8version>
dependency>
创建RedissonConfig
配置类
@ConfigurationProperties(prefix = "spring.redis")
@Configuration
@Data
public class RedissonConfig {
// 主机名
private String host;
// 端口
private String port;
// 使用那个数据库
private Integer database;
@Bean
public RedissonClient redissonClient(){
Config config = new Config();
// 使用单机Redis服务
config.useSingleServer()
// use "rediss://" for SSL connection
.setAddress(String.format("redis://%s:%s",host,port))
.setDatabase(database);
return Redisson.create(config);
}
}
创建配置文件
# Redis 配置
spring.redis.host=xxx
spring.redis.port=xxx
spring.redis.database=xxx
在业务代码中添加分布式锁
// 注入我们的RedissonClient
@Autowired
private RedissonClient redissonClient;
{
// 指定一个key来获取锁,如果是需要按不同的情况加锁的话,这样可以使用变量
RLock lock = redissonClient.getLock("LOCK_NAME");
try{
lock.tryLock(long waitTime, long leaseTime, TimeUnit unit);
//... 业务逻辑
}catch (InterruptedException ex) {
ex.printStackTrace();
}finally{
// 判断是否由当前线程持有锁
if (lock.isHeldByCurrentThread()) {
// 释放锁
lock.unlock();
}
}
}
tryLock
尝试获取锁 获取成功返回true 获取失败返回false
waitTime
尝试获取锁的等待时间,超过不再继续获取leaseTime
锁的持有时间,业务代码的执行时间如果超过该时间则抛出异常
- 可以设置为null 或者 -1 表示业务执行多久占用多久,这里其实使用了
看门狗
的一个机制,默认的持有时间是30秒,如果超时未执行完成,看门狗
会为我们自己续期一次。已保证业务代码执行完成。unit
时间单位