目录
一、如何实现分布式锁?
Redis 天生就可以作为一个分布式系统来使用,所以它实现的锁都是分布式锁。
Redis 可以通过 setnx 命令(set if not exists)命令实现分布式锁,实现方式如下所示:
# 加锁
setnx mylock 1
# 释放锁
del mylock
通过执行结果是否为1,可以判断是否成功获取到锁,如下图所示:

二、Redis 分布式锁存在什么问题?
Redis 分布式锁存在两个问题:
死锁问题
:如果在加锁之后,未设置过期时间、锁忘记释放、加锁后还没来得及释放锁就宕机了 这3种情况都会导致死锁问题。锁误删问题
:设置了超时时间,但是 线程执行超过过期时间 后锁误删问题。
2.1 解决死锁问题
1)方式一:set 升级
MySQL 中解决死锁问题是通过设置超时时间,Redis 也是如此,但是问题来了,第一步先加锁,然后再设置超时时间,那么就 不满足原子性了,那怎么办?
官方在 Redis 2.6.12 版本之后,新增了一个功能,我们可以使用一条命令既执行加锁操作,又设置过期时间,相当于:setnx + expire。如下图所示:

- 第1条命令加锁成功,并设置 30s 过期时间。
- 第2条命令跟在第1条命令后,还没有超过 30s,所以加锁失败。
2)方式二:setIfAbsent 新方法
setIfAbsent()
是 Redis 专门为分布式锁实现的原子操作,其中封装了获取 key、设置 key、设置过期时间等操作。
RedisUtils 工具类:
@Component
public class RedisUtils {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/**
* 原子性操作 加锁
*/
public boolean setIfAbsent(String key, String value, long timeout, TimeUnit unit) {
return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, value, timeout, unit));
}