前情提要:
- SETNX:将key的值设置为value,当且仅当key不存在(version>=1.0),对应springBoot RedisTemplate的setIfAbsent(key,value);
简单方法一
代码片
.
String lockKey = "lockKey";
Boolean result = stringRedisTemplate.opsValue.setIfAbsent(lockKey,"value");//jedis.setnx(key,value)
if(!result){
return "error_code";
}
//业务代码...
stringRedisTemplate.delete(lockKey);
可能出现的问题:
- 业务抛异常,锁无法释放。
- 业务代码的时候服务被kill,导致锁无法释放
- 加锁时间太短业务没执行被释放,太长影响性能,到底多少时间合适? – 可以使用timer实现,扫描key,延长过期时间
简单方式二(加超时时间,解决问题1,2)基本可用:
String lockKey = "lockKey";
//1
Boolean result = stringRedisTemplate.opsForValue.setIfAbsent(lockKey,"value");//jedis.setnx(key,value)
//2
stringRedisTemplate.expire(lockKey,10,TimeUnit.SECONDS)
//3 (合并1和2)
Boolean result = stringRedisTemplate.opsForValue.setIfAbsent(lockKey,"value",10,TimeUnit.SECONDS)
if(!result){
return "error_code";
}
try{
//业务代码...
}finally{
stringRedisTemplate.delete(lockKey);
}
- 说明:3代码可以解决1和2执行中间服务崩溃
可能出现的问题:
- 在高并发下A线程加的锁,被其他线程释放掉,导致锁基本无用
方式三(线程只能释放自己加的锁):
String lockKey = "lockKey";
String clientId = UUID.randomUUID.toString();
//3 (合并1和2)
Boolean result = stringRedisTemplate.opsForValue.setIfAbsent(lockKey,clientId,10,TimeUnit.SECONDS)
if(!result){
return "error_code";
}
try{
//业务代码...
}finally{
if(clientId.equals(stringRedisTemplate.opsForValue.get(lockKay))){
stringRedisTemplate.delete(lockKey);
}
}
Redisson实现分布式锁:
String lockKey = "lockKey";
RLock redissonLock = redisson.getLock(lockKey);
try{
redissonLock.lock();
//业务代码...
}finally{
redissonLock.unlock();
}