RedissonMultiLock + RedissonLock部分源码

本文介绍了Redisson的RedissonMultiLock和RedissonLock两种分布式锁的实现细节。RedissonMultiLock允许指定等待时间,如果在等待时间内无法获取锁则返回失败。RedissonLock在加锁时,若未指定超时时间,会自动续期,若指定了超时时间,则在该时间后释放锁。加锁和解锁操作均基于lua脚本,确保原子性。RedissonLock在加锁失败后会订阅消息并休眠等待锁释放。RedLock是多节点的分布式锁实现,需要半数以上节点加锁成功才认为成功。
摘要由CSDN通过智能技术生成

Redisson有两个类,分别是RedissonMultiLock和RedsissonLock,都可以实现加锁,但是里面的实现逻辑有些差别

RedissonMultiLock

RedissonMultiLock可以指定等待时间,也就是说,假如我指定了等待时间是2S,比如:
1.A线程来加锁,正常去执行业务逻辑
2.B线程也来加锁,此时会加锁失败,那B线程最多等待2S,如果超过了2S还没有获取到分布式锁,那B线程加锁就返回false,表示加锁失败

加锁

RedissonMultiLock和RedissonRedLock有关系
而RedissonRedLock大致的思想是:在加锁的时候,Redis必须是集群配置,加锁的时候,会依次去多台Redis机器上进行加锁,如果一半以上的锁加锁成功了,就认为是加锁成功了,这个点我没有去看代码验证,只是先看了下加锁和解锁的部分细节

org.redisson.RedissonMultiLock#tryLock(long, long, java.util.concurrent.TimeUnit)
在加锁的时候,会调用到这个方法,这里入参的意思分别是:
第一个waitTime是锁等待时间
leaseTime是锁加锁时间
TimeUnit是时间单位

我的理解是:线程A在加锁的时候,会使用leaseTime作为锁失效时间,如果没有指定,就是默认30S,然后进行锁续期;如果指定了,那就使用指定的阈值,并且不会自动化续期
线程B来加锁的时候,如果线程A已经对同一个key进行了加锁,那线程B最多等待waitTime时间,如果到了这个时间,线程B依旧没有获取到锁,那线程B加锁的方法就会返回false,表示加锁失败

public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {
    long newLeaseTime = -1;
    // 1.这里是在指定了超时时间的时候,会将新的超时时间设置为锁等待时间的2倍;这里我没怎么理解为什么要这么做
    if (leaseTime != -1) {
        newLeaseTime = unit.toMillis(waitTime)*2;
    }
    
    long time = System.currentTimeMillis();
    long remainTime = -1;
    // 2.如果waitTime不等于-1,就是指定了等待时间的场景下,将等待时间转换为毫秒
    if (waitTime != -1) {
        remainTime = unit.toMillis(waitTime);
    }

    // 3.这里的计算,会用remainTime / Redis机器的数量;所以:如果我指定的等待时间是2000ms,那这里获取到的lockWaitTime就是666ms
    long lockWaitTime = calcLockWaitTime(remainTime);
    
    int failedLocksLimit = failedLocksLimit();
    List<RLock> acquiredLocks = new ArrayList<RLock>(locks.size());
    // 4.对所有的Redis加锁机器进行遍历,然后依次去加锁,如果加锁失败的话,会进行一些列的处理;这里加锁失败的处理逻辑我还没有细看,后面再补充
    for (ListIterator<RLock> iterator = locks.listIterator(); iterator.hasNext();) {
        RLock lock = iterator.next();
        boolean lockAcquired;
        try {
        	// 4.1 如果等待时间未指定、锁超时时间未指定,那就调用下面这个方法即可
            if (waitTime == -1 && leaseTime == -1) {
                lockAcquired = lock.tryLock();
            } else {
            	// 4.2 反之,就会调用入参了waitTime和leaseTime的方法
                long awaitTime = Math.min(lockWaitTime, remainTime);
                lockAcquired = lock.tryLock(awaitTime, newLeaseTime, TimeUnit.MILLISECONDS);
            }
        } catch (RedisResponseTimeoutException e) {
            unlockInner(Arrays.asList(lock));
            lockAcquired = false;
        } catch (Exception e) {
            lockAcquired = false;
        }
        
        if (lockAcquired) {
            acquiredLocks.add(lock);
        } else {
            if (locks.size() - acquiredLocks.size() == failedLocksLimit()) {
                break;
            }

            if (failedLocksLimit == 0) {
                unlockInner(acquiredLocks);
                if (waitTime == -1 && leaseTime == -1) {
                    return false;
                }
                failedLocksLimit = failedLocksLimit();
                acquiredLocks.clear();
                // reset iterator
                while (iterator.hasPrevious()) {
                    iterator.previous();
                }
            } else {
                failedLocksLimit--;
            }
        }
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值