Redis学习(十一)Redis分布式锁导致死锁、锁误删的场景及解决方法

Redis分布式锁通过setnx实现,但存在死锁和锁误删问题。解决死锁可使用set命令的原子性操作或setIfAbsent方法。锁误删可通过设置锁标识和使用Redission或lua脚本来保证原子性。文章介绍了Redission的实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、如何实现分布式锁?

Redis 天生就可以作为一个分布式系统来使用,所以它实现的锁都是分布式锁。

Redis 可以通过 setnx 命令(set if not exists)命令实现分布式锁,实现方式如下所示:

# 加锁
setnx mylock 1
# 释放锁
del mylock

通过执行结果是否为1,可以判断是否成功获取到锁,如下图所示:


二、Redis 分布式锁存在什么问题?

Redis 分布式锁存在两个问题:

  1. 死锁问题:如果在加锁之后,未设置过期时间锁忘记释放加锁后还没来得及释放锁就宕机了 这3种情况都会导致死锁问题。
  2. 锁误删问题:设置了超时时间,但是 线程执行超过过期时间 后锁误删问题。

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));
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不愿放下技术的小赵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值