Redis实现分布式锁的几种方案

本文介绍了三种使用Redis实现分布式锁的方法,包括利用setnx和expire命令、setnx结合判断锁是否过期以及Redis 2.6.12版本后的set命令新增参数等方案,解决了并发环境下资源竞争的问题。

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

1.1方案一

        利用setnx和expire命令实现加锁。当一个线程执行setnx返回1,说明key不存在,该线程获得锁;当一个线程执行setnx返回0,说明key已经存在,则获取锁失败。expire就是给锁加一个过期时间。伪代码如下:

if(setnx(key,value)==1){
     expire(key,expireTime)
     try{
        //业务处理
     }finally{
       del(key)
     }
}

        该方案有一个致命问题,由于setnx和expire是两条Redis命令,不具备原子性,如果一个线程在执行完setnx()之后突然崩溃,导致锁没有设置过期时间,那么将会发生死锁。

1.2方案二

        利用setnx命令加锁,其中key是锁,value是锁的过期时间,1.通过setnx()方法尝试加锁,如果当前锁不存在,返回加锁成功。2. 如果锁已经存在则获取锁的过期时间,和当前时间比较,如果锁已经过期,则设置新的过期时间,返回加锁成功。伪代码如下:

    long expires = System.currentTimeMillis() + expireTime;
    String expiresStr = String.valueOf(expires);

    // 如果当前锁不存在,返回加锁成功
    if (setnx(key, expiresStr) == 1) {
        return true;
    }

    // 如果锁存在,获取锁的过期时间
    String currentValueStr = get(key);
    if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) {
        // 锁已过期,获取上一个锁的过期时间,并设置现在锁的过期时间
        String oldValueStr = jedis.getSet(lockKey, expiresStr);
        if (oldValueStr != null && oldValueStr.equals(currentValueStr)) {
            // 考虑多线程并发的情况,只有一个线程的设置值和当前值相同,它才有权利加锁
            return true;
        }
    }
        
    // 其他情况,一律返回加锁失败
    return false;

        此方案需要客户端时间同步,并且该线程的锁的过期时间可能被其他线程覆盖。

1.3方案三

        Redis2.6.12以上版本为set命令增加了可选参数,伪代码如下:

if(redis.set(key,value,"ex 180","nx")){
     //业务处理
     do something;
     //释放锁
     redis.delete(key);
}

        我们对锁设置了过期时间,即使锁的持有者后续发生崩溃而没有解锁,锁也会因为到了过期时间而自动解锁(即key被删除),不会发生死锁。

转载于:https://my.oschina.net/wuchanghao/blog/1827226

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值