基于set nx实现的分布式锁有以下问题:
-
不可重入:不能多次获取同一把锁。可重入锁的意义是在于防止死锁。
-
不可重试:线程在获取锁失败后,应该能多次尝试。
-
超时释放:业务还没执行完,锁就释放了。
-
主从一致性:如果Redis提供了主从集群,当我们向集群写数据时,主机需要异步的将数据同步给从机,而万一在同步过去之前,主机宕机了,就会出现死锁问题。概率低,同步是毫秒级.
redission分布式锁示例
@Resource
private RedissonClient redissonClient;
@Override
public Result seckillVoucher(Long voucherId) {
// 1.查询优惠券
SeckillVoucher voucher = seckillVoucherService.getById(voucherId);
// 2.判断秒杀是否开始
if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {
// 尚未开始
return Result.fail("秒杀尚未开始!");
}
// 3.判断秒杀是否已经结束
if (voucher.getEndTime().isBefore(LocalDateTime.now())) {
// 尚未开始
return Result.fail("秒杀已经结束!");
}
// 4.判断库存是否充足
if (voucher.getStock() < 1) {
// 库存不足
return Result.fail("库存不足!");
}
Long userId = UserHolder.getUser().getId();
//创建锁对象 这个代码不用了,因为我们现在要使用分布式锁
//SimpleRedisLock lock = new SimpleRedisLock("order:" + userId, stringRedisTemplate);
RLock lock = redissonClient.getLock("lock:order:" + userId);
//获取锁对象
boolean isLock = lock.tryLock();
//加锁失败
if (!isLock) {
return Result.fail("不允许重复下单");
}
try {
//获取代理对象(事务)
IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();
return proxy.createVoucherOrder(voucherId);
} finally {
//释放锁
lock.unlock();
}
}
redission分布式锁
-
可重入
-
trylock可重试
-
看门狗机制,锁续期,可以用来解决锁提前释放的问题,默认30s过期,每10s检查一次,如果发现业务代码还在执行,后台线程就主动续约。
为什么大家都用redis分布式锁?
-
首先是快
-
redission框架出来的时间较早,功能比较完善 先入为主