Redisson实现分布式锁

592 阅读2分钟

     上一篇文档我们探讨了redis实现分布式锁以及它遇到的问题,为了解决这些可能会写很多代码,一不小心可能就会产生bug。其实这些问题Redisson都帮我们解决了,那么今天我们来探讨一下Redisson实现分布式锁

首先来看一下代码示例:

public class RedissonLock {    
    public static void main(String[] args) {        
        Config config = new Config();
        // 单机模式        
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");        
        RedissonClient redissonClient = Redisson.create(config);        
        RLock rLock = redissonClient.getLock("key");        
        try { 
            // 超时获取锁(100毫秒超时时间、10毫秒锁的时间)       
            rLock.tryLock(100,10,TimeUnit.MILLISECONDS);                       
            Thread.sleep(1000);                 
            } catch (InterruptedException e) {            
                e.printStackTrace();        
        } finally {            
            rLock.unlock();            
            redissonClient.shutdown();        
        }    
    }
}

比起redis去实现分布式锁要考虑很多场景,这种写法是不是代码简洁了很多。核心代码其实就三行,如果我们跟踪进去就会看到下面的源码

return this.commandExecutor.evalWriteAsync(this.getName(), LongCodec.INSTANCE, command,
"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]);",
Collections.singletonList(this.getName()), new Object[]{this.internalLockLeaseTime, this.getLockName(threadId)});

       我们从中还是可以看懂一点,其实现思路还是那个思路,只不过Redisson用lua脚本把我们实现了,lua脚本具有原子性,操作比我们用代码实现更加严谨,最主要Redisson被广泛使用,是经过验证的,不会有什么bug。

      我们之前提到过一个问题,这个锁的超时时间设置多少合适呢?如果时间到了业务代码没执行完该怎么办?Redisson是这么实现的,获取锁的线程会启动一个后台线程去监视这个线程,每隔一段时间就去轮训一次看看这个线程有没有执行结束,如果没有结束,那么延长时间为超时时间的3分之一秒,如果你没有设置超时时间那么Redisson默认设置30秒,那么这个轮训间隔时间就是10秒,RedissonLock.this.scheduleExpirationRenewal(threadId);就是后台线程启动的定时任务