分布式锁(设置锁和过期时间)
问题描述:
随着业务发展的需要,原单体单机部署的系统被演化分成分布式集群系统后,由于分布式系统多线程、多进程且分布在不同机器上,这将使原单机部署情况下的并发控制锁策略失效,单纯的Java API并不能提供分布式锁的能力。为了解决这个问题就需要一种跨JVM的互斥机制来控制共享资源的访问,这就是分布式锁要解决的问题
分布式锁主流的实现方案:
1、基于数据库实现分布式锁
2、基于缓存(Redis等)
3、基于Zookeeper
每一种分布式锁解决方案都有各自的优缺点。
解决方案:基于Redis实现分布式锁
redis:命令
# set sku:1:info "OK" NX PX 10000
EX second:设置键的过期时间为seconds秒,SET key value EX second效果等同于SETEX key second value
NX::只在键不存在时,才对键进行设置操作,SET key value NX效果等同于SETNX key value
XX:只在键已经存在时,才对键进行设置操作
DEL:释放锁
设置过期时间解决锁一直不能释放的问题
上锁之后出现异常无法设置过期时间:上锁时同时设置过期时间 set users 10 nx ex 10 既上锁又设置过期时间同步进行。
@GetMapping("/testLock")
public void testLock(){
//1、获取锁, setnx
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "111", 3, TimeUnit.SECONDS);
//2、获取锁成功,查询num的值
if(lock){
Object value = redisTemplate.opsForValue().get("num");
//2.1 判断num为空return
if(StringUtils.isEmpty(value)){
return;
}
//2.2 有值就转成int
int num = Integer.parseInt(value + "");
//2。3 把redis的num加1
redisTemplate.opsForValue().set("num", ++num);
//2.4 释放锁,del
redisTemplate.delete("lock");
}else {
//3 获取锁失败,每个0.1秒再获取
try{
Thread.sleep(100);
testLock();
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
存在问题:误删,锁释放错了
a:先操作
1、上锁
2、具体操作
服务器卡顿
3、锁自动释放
b:抢到锁,具体操作
a服务器反应过来,进行操作,手动释放锁,释放了b的锁
方法:使用UUID表示不同操作
1、set lock uuid nx ex 10
2、释放锁时,首先判断当前uuid和要释放锁的uuid是否一样。
@GetMapping("/testLock")
public void testLock(){
String uuid = UUID.randomUUID().toString();
//1、获取锁, setnx
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid, 3, TimeUnit.SECONDS);
//2、获取锁成功,查询num的值
if(lock){
Object value = redisTemplate.opsForValue().get("num");
//2.1 判断num为空return
if(StringUtils.isEmpty(value)){
return;
}
//2.2 有值就转成int
int num = Integer.parseInt(value + "");
//2。3 把redis的num加1
redisTemplate.opsForValue().set("num", ++num);
//2.4 释放锁,del、判断比较uuid是否一样
if(redisTemplate.opsForValue().get("lock").equals(uuid)){
redisTemplate.delete("lock");
}
}else {
//3 获取锁失败,每个0.1秒再获取
try{
Thread.sleep(100);
testLock();
}catch(InterruptedException e){
e.printStackTrace();
}
}
}

浙公网安备 33010602011771号