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