美文网首页
Redission实现分布式锁(二)

Redission实现分布式锁(二)

作者: 倚仗听江 | 来源:发表于2020-11-23 17:10 被阅读0次

    Redission是通过lua脚本来访问Redis来确保业务逻辑执行的原子性的。
    以下就是Redission中lua加锁的代码

    if (redis.call('exists', KEYS[1]) == 0) then 
            redis.call('hset', KEYS[1], ARGV[2], 1);
             redis.call('pexpire', KEYS[1], ARGV[1]); 
             return nil;
             end;
    if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then
            redis.call('hincrby', KEYS[1], ARGV[2], 1);
            redis.call('pexpire', KEYS[1], ARGV[1]); 
            return nil;
            end;
    return redis.call('pttl', KEYS[1]);
    

    KEYS[1]:就代表加的那把锁的key,我只需要判断这个key值是否存在就能知道锁是否被线程持有。
    ARGV[1]:表示锁的有效期,默认30s
    ARGV[2]:表示表示加锁的客户端ID
    首先先判断这把锁的key值是否存在,如果不存在,那就可以直接加锁。如果已存在,就要判断一下持有锁的线程是不是当前线程。所以用hexist来判断这个hash中是否存在当前线程的ID,如果存在就说持有锁的就是当前线程,则可以再次进入。将value值加1并延长锁的有效时间。如果不是当前线程的ID,那么就会返回剩余的生存时间,当前线程就会进入一个循环,不断的去尝试获取锁。

    以下是Redisson释放锁的lua代码

    if (redis.call('exists', KEYS[1]) == 0) then
           redis.call('publish', KEYS[2], ARGV[1]);
            return 1; 
            end;
    if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then 
         return nil;
         end;
    local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); 
    if (counter > 0) then
         redis.call('pexpire', KEYS[1], ARGV[2]); 
         return 0; 
    else redis.call('del', KEYS[1]); 
         redis.call('publish', KEYS[2], ARGV[1]); 
         return 1;
         end;
    return nil;
    

    key 不存在,说明锁已释放,直接执行 publish 命令发布释放锁消息并返回 1。
    key 存在,但是 field 在 Hash 中不存在,说明自己不是锁持有者,无权释放锁,返回 nil。
    因为锁可重入,所以释放锁时不能把所有已获取的锁全都释放掉,一次只能释放一把锁,因此执行 hincrby 对锁的值减一。
    释放一把锁后,如果还有剩余的锁,则刷新锁的失效时间并返回 0;如果刚才释放的已经是最后一把锁,则执行 del 命令删除锁的 key,并发布锁释放消息,返回 1。

    相关文章

      网友评论

          本文标题:Redission实现分布式锁(二)

          本文链接:https://www.haomeiwen.com/subject/urxviktx.html