什么时候用分布式锁
在项目中为保证共享变量的准确性,一般要加锁,一般想到的是synchronize,那什么时候要用分布式锁呢?我们在部署我们的服务的时候,可能会部署多台服务器,这样就会导致访问多台服务器的同一个接口,同时执行相同的逻辑,可能会同时更改数据,可能造成数据不对的问题,可以想象成不同系统中的多线程(比如A想把1改成2,B在A改后的基础上加1,成为3,结果它俩同时改,结果就成了2,这样结果就不对了),这个时候就用到分布式锁了。
分布式锁怎么用
分布式锁有三种实现方式
1、用Redisson实现分布式锁
一般是用了Redis,则选择用Redisson实现分布式锁
(1)引入Redisson的依赖
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.6.5</version>
</dependency>
(2)添加配置文件
@Configuration
public class RedissonConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private String port;
@Bean
public RedissonClient getRedisson(){
Config config = new Config();
config.useSingleServer().setAddress("redis://"+host+":"+port);
return Redisson.create(config);
}
}
(3)业务代码中使用
// 设置锁定资源名称 获取锁对象
RLock rLock = redissonClient.getLock("redisson:lock:key");
try {
// 尝试加锁,最多等5秒,上锁以后10秒自动解锁
rLock.tryLock(5,10,TimeUnit.SECONDS);
// 业务操作代码
}
}catch (InterruptedException e){
e.printStackTrace();
}
finally {
// 释放锁
rLock.unlock();
}
我用了tryLock加锁,加锁还有多种方式
// 普通用法
rLock.lock();
// 支持过期解锁功能,5秒钟以后自动解锁, 无需调用unlock方法手动解锁
rLock.lock(5, TimeUnit.SECONDS);
// 尝试加锁,最多等5秒,上锁以后10秒自动解锁
rLock.tryLock(5,10,TimeUnit.SECONDS);
......
2、用Mysql的行锁实现分布式锁
在争抢锁的时候向数据库写一条记录,插入成功表示当前线程获取到了锁,插入失败表示当前锁被占用,一会儿接着抢,直到抢到或者超时为止。
为什么会有插入失败呢,因为Mysql支持行锁(InnoDB引擎),行锁的话,同一时间只能有一个线程只能操作一行数据,所以会有插入失败的情况,这也就保证了只会有一个线程获取到锁然后执行任务。
3、用Zookeeper的临时节点实现分布式锁
使用Zookeeper的临时节点实现分布式锁,前提是我们项目用了Zookeeper。
为什么能用Zookeeper实现分布式锁呢,是因为Zookeeper的写入都是顺序的,在一个节点创建之后,其他请求再次创建便会失败,如果节点删除,也会通知别人来请求创建节点。这也就保证了只会有一个线程获取到锁然后执行任务。
这三种实现方式,用Redisson实现的分布式锁是相对比较好的。