本篇主要讲解Redisson中得RedLock实现,但是很多知识因为和前面一样,就直接省略了
RedLock 原理理一下:
(1)获取当前时间戳,单位是毫秒
(2)和RedissonMultiLock一样,一次轮询尝试去每个机器上创建锁,需要加一个超时时间,如果超过一定时间就表示获取锁失败
(3)尝试在大多数节点上建立一个锁,如果3个节点就要求创建 n/2 + 1 = 2个节点上创建锁
(4)客户端计算建立锁的时间,如果在规定时间内,建立锁成功,就代表加锁成功
(5)如果建立锁失败,那么就会依次的删除锁
(6)只要别人创建了锁,那么你就得不停得轮询去尝试获取锁
public static void main(String[] args) throws Exception {
//构建一个配置信息对象
Config config = new Config();
config.useClusterServers()
//定时扫描连接信息 默认1000ms
.setScanInterval(2000)
.addNodeAddress("redis://127.0.0.1:7001");
//因为Redisson 是基于redis封装的一套便于复杂操作的框架
//所以这里构建对象肯定是创建一些与redis的连接
RedissonClient redisson = Redisson.create(config);
RLock lock1 = redisson.getLock("lock1");
RLock lock2 = redisson.getLock("lock2");
RLock lock3 = redisson.getLock("lock3");
RedissonRedLock redLock = new RedissonRedLock(lock1,lock2,lock3);
redLock.lock();
//释放锁
redLock.unlock();
} 但是这个RedLock的源码相当的简单,为什么?我们学习了RedissonMultiLock的源码,其实你们想想RedLock的逻辑,其实是不是和RedissonMultiLock极其的相似,
对的,没错,RedLock 就是RedissonMultiLock 的一个子类,里面仅仅覆盖了几个方法
public class RedissonRedLock extends RedissonMultiLock {
/**
* Creates instance with multiple {@link RLock} objects.
* Each RLock object could be created by own Redisson instance.
*
* @param locks - array of locks
*/
public RedissonRedLock(RLock... locks) {
super(locks);
}
//允许失败的个数
@Override
protected int failedLocksLimit() {
return locks.size() - minLocksAmount(locks);
}
//最少要获取几个锁
//如果size = 3,计算出来=2
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);
}
}
public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {
// try {
// return tryLockAsync(waitTime, leaseTime, unit).get();
// } catch (ExecutionException e) {
// throw new IllegalStateException(e);
// }
long newLeaseTime = -1;
if (leaseTime != -1) {
newLeaseTime = unit.toMillis(waitTime)*2;
}
long time = System.currentTimeMillis();
long remainTime = -1;
if (waitTime != -1) {
remainTime = unit.toMillis(waitTime);
}
//lockWitTime = 1500ms
long lockWaitTime = calcLockWaitTime(remainTime);
//以前MultiLock 是默认0,但是对于RedLock n- (n/2+1) 假设N=3.计算出来就是1
int failedLocksLimit = failedLocksLimit();
List<RLock> acquiredLocks = new ArrayList<RLock>(locks.size());
for (ListIterator<RLock> iterator = locks.listIterator(); iterator.hasNext();) {
RLock lock = iterator.next();
boolean lockAcquired;
try {
if (waitTime == -1 && leaseTime == -1) {
lockAcquired = lock.tryLock();
} else {
long awaitTime = Math.min(lockWaitTime, remainTime);
//获取每个小锁 超时时间是1500ms
lockAcquired = lock.tryLock(awaitTime, newLeaseTime, TimeUnit.MILLISECONDS);
}
} catch (Exception e) {
lockAcquired = false;
}
if (lockAcquired) {
acquiredLocks.add(lock);
} else {
//加锁失败会走到这里,这里是什么逻辑?
//之前multiLock 任何一个小锁加锁失败,都会退出循环,就是代表获取锁失败,
//但是注意外面的死循环,会再次进来尝试获取锁
//那么现在如果是RedLock 会是什么逻辑?
//那么如果是 3-2 = 1 == 1
//其实再RedLock 中也代表加锁成功你们想想
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 {
//将加锁失败限制-1,就是代表你还剩余几次允许失败的次数
failedLocksLimit--;
}
}
if (remainTime != -1) {
remainTime -= (System.currentTimeMillis() - time);
time = System.currentTimeMillis();
if (remainTime <= 0) {
unlockInner(acquiredLocks);
return false;
}
}
}
if (leaseTime != -1) {
List<RFuture<Boolean>> futures = new ArrayList<RFuture<Boolean>>(acquiredLocks.size());
for (RLock rLock : acquiredLocks) {
RFuture<Boolean> future = rLock.expireAsync(unit.toMillis(leaseTime), TimeUnit.MILLISECONDS);
futures.add(future);
}
for (RFuture<Boolean> rFuture : futures) {
rFuture.syncUninterruptibly();
}
}
return true;
} 那么释放锁呢,其实也就是依次得去调用底层RedissonLock得释放锁得API而已
本文标题:Redisson 源码初探(八) RedLock
本文链接:https://blog.quwenai.cn/post/2889.html
版权声明:本文不使用任何协议授权,您可以任何形式自由转载或使用。






还没有评论,来说两句吧...