redis分布式锁应用场景:秒杀、大促之类的活动,在并发情况下对同一资源的访问
redis实现分布式锁:
@Autowired
@Qualifier("redisTemplate")
private RedisTemplate<String, Object> redisTemplate;
public Boolean redisLock() throws Exception {
//生成分布式锁redis key
String key = "REDIS_KEY";
//生成分布式锁redis value
String value = Thread.currentThread().getId() + ":" + UUID.randomUUID();
try {
logger.info("分布式锁key:" + key + ";分布式锁value:" + value);
//加锁
Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, value, 60, TimeUnit.SECONDS);
logger.info("添加分布式锁结果:" + flag);
if (!flag) {
throw new Exception("当前操作已有用户在处理,请稍后再试");
}
//业务逻辑
} catch (Exception e) {
logger.info(e.getMessage(), e);
throw new Exception(e.getMessage());
} finally {
logger.info("删除分布式锁处理开始");
//执行完方法后,删除分布式锁
//校验是否是同一线程加的锁 只有同一线程加的锁才能去释放锁
if(value.equals(redisTemplate.opsForValue().get(key))) {
Boolean flag = redisLockUtils.unLock(key, value);
logger.info("删除分布式锁结果:" + flag);
}
}
return true;
}
上面通过redis实现的分布式锁 针对一般的业务是可用的 但是还是会存在一个问题 由于我们考虑到锁的超时时间需要根据业务情况来定 不能设置太长 也不能设置太短 在这种情况下 可能会在某一时间方法执行的时间很长 或者jvm在进行垃圾回收(并行算法时回收期间会暂停程序的执行) 获取锁的线程业务还没执行完就释放了锁 导致其他线程获取锁成功 针对上面的情况 我们可以使用redisson进行分布式锁的实现
redisson实现分布式锁:
添加依赖:
<dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.6.5</version> </dependency>
public Boolean redisLock() throws Exception {
//生成分布式锁redis key
String key = "REDIS_KEY";
RLock redissonLock = redissonClient.getLock(key);
try {
//加锁
redissonLock.lock();
//业务逻辑
} catch (Exception e) {
logger.info(e.getMessage(), e);
throw new Exception(e.getMessage());
} finally {
logger.info("删除分布式锁处理开始");
redissonLock.unlock();
}
return true;
}
通过redisson实现分布式锁 在并发情况下 只有第一个线程才能执行 redissonLock.lock(); 加锁成功。底层相当于执行了setIfAbsent(key, value, 30, TimeUnit.SECONDS)这个命令。 redissonLock.lock()默认超时时间30秒,这行代码在后台会开启一个定时续命的分线程,每隔一段时间(设置的超过时间的三分之一。 默认30秒超时 那么每隔10秒)检查当前线程是否还持有锁,如果持有则延长锁的时间,而其他线程会阻塞在redissonLock.lock()这行代码,通过while循环尝试加锁
redisson实现分布式锁原理图: