Redis分布式锁中getSet方法疑问

来源:13-8 redis分布式锁

揍猫的老鼠

2018-04-10

Redis分布式锁中,当锁过期的时候,如果多个客户端同时执行getSet()方法,那么虽然最终只有一个线程可以加锁,但是这个线程的锁的过期时间可能被其线程覆盖。

比如key的时间是10000,线程A的过期时间是10010,线程B的过期时间是10020。当线程A执行了getSet方法拿到了锁,那么key里面的值为10010,然后线程B也去抢锁,执行getSet方法,虽然返回的值是10010,与B线程的锁的过期时间不等,B拿不到锁,但是,此时key的值被线程B改为10020了。  这个情况怎么办?


写回答

1回答

廖师兄

2018-04-10

"比如key的时间是10000,线程A的过期时间是10010"  ,不太明白你的意思,可否直接拿课程中redis锁的代码来说明呢


-------更新----------

但此时key的value变成了10020, 但是返回的是10010。 你看看这边文章前面部分的文字说明 https://blog.csdn.net/abbc7758521/article/details/77990048 , 结合我给的代码(下方) 

/**
 * 加锁
 * @param key
 * @param value 当前时间+超时时间
 * @return
 */
public boolean lock(String key, String value) {
    if(redisTemplate.opsForValue().setIfAbsent(key, value)) {
        return true;
    }
    //currentValue=A   这两个线程的value都是B  其中一个线程拿到锁
    String currentValue = redisTemplate.opsForValue().get(key);
    //如果锁过期
    if (!StringUtils.isEmpty(currentValue)
            && Long.parseLong(currentValue) < System.currentTimeMillis()) {
        //获取上一个锁的时间
        String oldValue = redisTemplate.opsForValue().getAndSet(key, value);
        if (!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)) {
            return true;
        }
    }

    return false;
}


0
5
慕雪0381783
问题应该是这样,redis服务器中锁的value是100,现在有A、B两个进程想要竞争锁,这进程A在200的时候竞争锁,进程B在300的时候竞争锁,但是由于网络的原因,两个进程同时获取到了redis服务器中锁的value,也就是100,比较之后发现锁已经过期,两个进程便同时竞争锁。假设进程A获得了锁,redis服务器中锁的value变成了200+TIMEOUT;进程B在getSet的时候得到的是200+TIMEOUT,不等于100,所以获取锁失败,但进程B已经将redis服务器中锁的value改成了300+TIMEOUT。那么,当进程A完成操作后,想要主动释放锁的时候,就会释放失败。这样会出现这样的情况,进程B再次尝试获取锁的时候,误以为锁仍然被其他进程占有,直到TIMEOUT时间过后发现锁过期,再次竞争锁(因为进程B的当前时间是300,redis服务器中锁的值是300+TIMEOUT)。只要出现一次锁过期的情况,并且在锁过期的时候有并发的竞争锁,就会一直出现这个问题。
2018-08-22
共5条回复

Spring Boot双版本(1.5/2.1) 打造企业级微信点餐系统

从0到1开发中小型企业级Java应用,并学会迭代重构技巧

6410 学习 · 5247 问题

查看课程