分布式锁源码剖析(3) Redisson的MultiLock和RedLock

MultiLock

MultiLock:将多个锁合并为一个大锁,对一个大锁进行统一的申请加锁以及释放锁,一次性锁定多个资源,再去处理一些事情,然后事后一次性释放所有的资源对应的锁。

maven配置文件:

 <dependency>
         <groupId>org.redisson</groupId>
         <artifactId>redisson</artifactId>
         <version>3.8.1</version>
</dependency>

代码示例:

Config config = new Config();
Config config = new Config();
config.useClusterServers()
    .addNodeAddress("redis://192.168.31.114:7001")
    .addNodeAddress("redis://192.168.31.184:7002");

RedissonClient redisson = Redisson.create(config);

RLock lock1 = redisson.getLock("lock1");
RLock lock2 = redisson.getLock("lock2");
RLock lock3 = redisson.getLock("lock3");

RedissonMultiLock lock = new RedissonMultiLock(lock1, lock2, lock3);
// locks: lock1 lock2 lock3
lock.lock();
lock.unlock();

核心源码:

根据锁的个数,计算出基础的等待时间。

long baseWaitTime = locks.size() * 1500;

循环尝试获取锁,直到获取锁成功后返回。

while (true) {
    if (tryLock(waitTime, leaseTime, unit)) {
        return;
    }
}

调用RedissonLock的tryLock方法,尝试获取锁,如果获取锁成功,把锁添加到集合。

List<RLock> acquiredLocks = new ArrayList<RLock>(locks.size());
lockAcquired = lock.tryLock();
acquiredLocks.add(lock);

如果获取锁超时就会退出,重新再次死循环尝试获取锁。

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--;
}

RedLock

maven配置文件:

 <dependency>
         <groupId>org.redisson</groupId>
         <artifactId>redisson</artifactId>
         <version>3.8.1</version>
</dependency>

代码示例:

Config config = new Config();
config.useClusterServers()
    .addNodeAddress("redis://192.168.31.114:7001")
    .addNodeAddress("redis://192.168.31.184:7002");

RedissonClient redisson = Redisson.create(config);

RLock lock1 = redisson.getLock("lock1");
RLock lock2 = redisson.getLock("lock2");
RLock lock3 = redisson.getLock("lock3");

RedissonRedLock lock = new RedissonRedLock(lock1, lock2, lock3);
// locks: lock1 lock2 lock3
lock.lock();
lock.unlock();

算法原理:

1、获取当前时间戳,单位是毫秒。

2、跟上面类似,轮流尝试在每个master节点上创建锁,过期时间较短,一般就几十毫秒,在每个节点上创建锁的过程中,需要加一个超时时间,一般来说比如几十毫秒如果没有获取到锁就超时了,标识为获取锁失败。

3、尝试在大多数节点上建立一个锁,比如3个节点就要求是2个节点(n / 2 +1)。

4、客户端计算建立好锁的时间,如果建立锁的时间小于超时时间,就算建立成功了。

5、要是锁建立失败了,那么就依次删除已经创建的锁。

6、只要别人创建了一把分布式锁,你就得不断轮询去尝试获取锁。

核心源码:

是RedissonMultiLock的一个子类,RedLock算法的实现,是依赖于MultiLock的一个机制来实现。主要通过重写failedLocksLimit和calcLockWaitTime实现,只有n/2+1个加锁操作失败之后,才会重新去循环加锁。

public class RedissonRedLock extends RedissonMultiLock {

    public RedissonRedLock(RLock... locks) {
        super(locks);
    }

    @Override
    protected int failedLocksLimit() {
        return locks.size() - minLocksAmount(locks);
    }
    
    protected int minLocksAmount(final List<RLock> locks) {
        return locks.size()/2 + 1;
    }

    @Override
    protected long calcLockWaitTime(long remainTime) {
        return Math.max(remainTime / locks.size(), 1);
    }
    
    @Override
    public void unlock() {
        unlockInner(locks);
    }
}

猜你喜欢

转载自blog.csdn.net/qq40988670/article/details/85276593