分布锁

redission 分布锁

redission 分布锁使用了map 这种数据结构,key为锁的名称,map的key客户端,value为重入的个数

代码进行分析,大致代码都写到RedissionLock这个类里。

加锁:

ivate void lock(long leaseTime, TimeUnit unit, boolean interruptibly) throws InterruptedException {
        long threadId = Thread.currentThread().getId();
        //先进行获取锁
        Long ttl = this.tryAcquire(leaseTime, unit, threadId);
        //如果获取锁失败
        if (ttl != null) {
            //进行订阅,注意这是一个同步操作,如果channel 里没有消息,会一直阻塞,当其他线程进行锁的释放,会进行消息的发送
            //如果正常操作的话,会进行轮询,但这样对redis 压力太大,所以使用发布订阅来实现
            RFuture<RedissonLockEntry> future = this.subscribe(threadId);
            this.commandExecutor.syncSubscription(future);

            try {
                while(true) {
                    ttl = this.tryAcquire(leaseTime, unit, threadId);
                    if (ttl == null) {
                        return;
                    }

                    if (ttl >= 0L) {
                        try {
                            this.getEntry(threadId).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
                        } catch (InterruptedException var13) {
                            if (interruptibly) {
                                throw var13;
                            }

                            this.getEntry(threadId).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
                        }
                    } else if (interruptibly) {
                        this.getEntry(threadId).getLatch().acquire();
                    } else {
                        this.getEntry(threadId).getLatch().acquireUninterruptibly();
                    }
                }
            } finally {
                this.unsubscribe(future, threadId);
            }
        }
    }

tryAcquire 里执行操作就是如下的代码:

//判断该锁是否存在,如果该锁不存在
if (redis.call('exists', KEYS[1]) == 0) 
	向map类型中添加数据, key为客户端id ,value 为 1 ,表示当前锁重入的个数为1
	then redis.call('hset', KEYS[1], ARGV[2], 1); 
	设置过期时间 ,默认为30秒
	redis.call('pexpire', KEYS[1], ARGV[1]); return nil; end; 
	
//如果存在该锁,并且该锁的持有者和当前客户端id相同
if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) 
	//将重入的个数加 1 
	then redis.call('hincrby', KEYS[1], ARGV[2], 1); 
	redis.call('pexpire', KEYS[1], ARGV[1]); 
	返回0
	return nil; end; 

//上述都不符合的话,就返回该key的过期时间
return redis.call('pttl', KEYS[1]);


key1 是要加锁的key

argv1 锁的key默认生存时间

argv2 加锁的客户端id,为生成的 UUID + thread_id ,UUID会在redission客户端对象创建的时候生成

 

释放锁:


0代表释放失败,1代表释放成功

//如果锁不存在
if (redis.call('exists', KEYS[1]) == 0) 
//发送释放锁的消息,返回1 
	then redis.call('publish', KEYS[2], ARGV[1]); return 1; end;
//如果持有该锁的客户端id 不是当前id ,释放锁失败	
if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then return nil;end; 

//如果锁的持有者和当前客户端id一致,将可重如个数-1 
local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); 
//如果当前可重入锁的个数大于0,说明锁不可以被释放
if (counter > 0) then redis.call('pexpire', KEYS[1], ARGV[2]); return 0;
 
//如果当前可重入锁的个数为0,说明锁可以被释放,并进行消息的发送
else redis.call('del', KEYS[1]); redis.call('publish', KEYS[2], ARGV[1]); return 1; end; 

//否则返回null 
return nil;

详细信息可以查看 分布式锁

 

zookepper 实现分布锁:

详见 zookeeper 实现分布锁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值