赞
踩
命令:setnx key value
对应RedisTemplate方法:setIfAbsent
在指定的 key 不存在时,为 key 设置指定的值
String lockKey = "key";
//拿锁
boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey,"value");
if(!result){
return "error";
}
/*
* 处理代码
*/
//释放锁
stringRedisTemplate.delete(lockKey);
容易出现的问题:出现异常容易死锁
String lockKey = "key";
try{
//拿锁
boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey,"value");
if(!result){
return "error";
}
/*
* 处理代码
*/
}finally{
//释放锁
stringRedisTemplate.delete(lockKey);
}
容易出现的问题:程序终止发生死锁
String lockKey = "key";
try{
//拿锁
boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey,"azheng",10,TimeUnit.SECONDS);
if(!result){
return "error";
}
/*
* 处理代码
*/
}finally{
//释放锁
stringRedisTemplate.delete(lockKey);
}
容易出现的问题:(执行超时,锁提前被释放问题)高并发下容易出现问题,线程1在程序没有执行完情况下锁过期被释放,但是,这时候线程2拿到锁继续执行,线程2还未执行完的时候,锁这时候却被线程1释放。这样会一直无线循环下去锁出现永久失效。。。锁一直被其他线程提前释放。
String clientId = UUID.randomUUID().toString(); String lockKey = "key"; try{ //拿锁 boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey,clientId,10,TimeUnit.SECONDS); if(!result){ return "error"; } /* * 处理代码 */ }finally{ if(clientId.equals(stringRedisTemplate.opsForValue().get(lockKey))){ //释放锁 stringRedisTemplate.delete(lockKey); } }
容易出现的问题:锁不会被其他线程释放,但锁还是会被超时释放,会被其它线程拿到锁。
解决锁超时带来的一系列问题
守护线程定时扫描的时间为: 锁超时时间的三分之一左右。
不存在性能问题,因为只有拿到锁的人才会有守护线程。但实际上同一时刻只有一个线程会拿到锁。
容易出现的问题:redis 宕机之后锁数据丢失,重启后导致两个线程同时持有锁,比如线程1拿到锁执行逻辑,然后此时Redis重启导致锁的数据丢了,然后线程2又可以拿到锁了。
Redis作者引入红锁的概念,就是集群模式下获取锁的时候,必须在一半以上的节点都获取到锁才算成功,保障锁数据不丢失。
基于Redis的Redisson红锁RedissonRedLock对象实现了Redlock介绍的加锁算法。该对象也可以用来将多个RLock对象关联为一个红锁,每个RLock对象实例可以来自于不同的Redisson实例
RLock lock1 = redissonInstance1.getLock("lock1");
RLock lock2 = redissonInstance2.getLock("lock2");
RLock lock3 = redissonInstance3.getLock("lock3");
RedissonRedLock lock = new RedissonRedLock(lock1, lock2, lock3);
// 同时加锁:lock1 lock2 lock3
// 红锁在大部分节点上加锁成功就算成功。
lock.lock();
...
lock.unlock();
以上逻辑自行实现过于复杂,所以需要引入第三方包Redisson.
compile 'org.redisson:redisson:3.12.3'
@Autowired
private Redisson redisson;
String lockKey = "key";
//获取锁对象
RLock lock = redisson.getLock(lockKey);
try{
//加锁
lock.lock(3, TimeUnit.SECONDS);
/*
* 处理代码
*/
}finally{
//释放锁
lock.unlock();
}
原理图
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。