redisson可重复锁的执行过程

tryLock→Redisson.tryLockAsync获取当前线程ID,默认无参数的trylock方法

会默认赋值waittime=-1(重试最大等待时间),leaseTime=-1存活时间,时间类型=null,线程ID=当前线程ID

→Redisson.tryAcquireOnceAsync

leaseTime默认值等于-1,走

方法,this.commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout()默认为30秒

参数waitTime=-1,leaseTime=30秒,Time.unit为毫秒TimeUnit.MILLISECONDS,线程ID,redis命令(不知道干什么用)

tryLockInnerAsync执行Lua脚本

  1. if (redis.call('exists', KEYS[1]) == 0)

判断key值是否存在,如果不存在

redis.call('hincrby', KEYS[1], ARGV[2], 1) 存入key值

redis.call('pexpire', KEYS[1], ARGV[1]) 设置存活时间

return nil; end 返回结束

如果key值存在

if (redis.call('hexists', KEYS[1], ARGV[2]) == 1)判断当前锁持有者是否是自己

如果是自己

"redis.call('hincrby', KEYS[1], ARGV[2], 1); hashkey中的value +1

同时更新持续时间

redis.call('pexpire', KEYS[1], ARGV[1]);

return nil; end 返回结束

如果持有锁的人不是自己,直接返回0;

public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {

//时间毫秒化

long time = unit.toMillis(waitTime);

long current = System.currentTimeMillis();

long threadId = Thread.currentThread().getId();

//第一次尝试获取锁

Long ttl = this.tryAcquire(waitTime, leaseTime, unit, threadId);

//如果剩余时间为Null 证明已经获取到锁 直接返回

if (ttl == null) {

return true;

} else {

// 先用得到第一次尝试获取锁消耗的时间,然后用最大尝试时间减去得到剩余时间

time -= System.currentTimeMillis() - current;

//如果剩余时间小于0 证明超时,直接返回获取锁失败

if (time <= 0L) {

this.acquireFailed(waitTime, unit, threadId);

return false;

} else {

//再次获取当前时间

current = System.currentTimeMillis();

//订阅该线程ID释放锁的消息

//需要注意,当线程第一次获取锁失败后,并非立即发起请求,而是等待已经获取锁成功的线程执行完毕后释放锁,

//然后再次发起获取线程请求,故当第一次释放锁成功后的Lua脚本中有publish发布锁已释放的动作

//此时,当前线程已订阅部分,才会根据接收到释放消息去再次发起请求。

RFuture<RedissonLockEntry> subscribeFuture = this.subscribe(threadId);

//如果在剩余时间内没有接收到锁释放的消息,直接返回获取锁失败,同时取消订阅

if (!subscribeFuture.await(time, TimeUnit.MILLISECONDS)) {

if (!subscribeFuture.cancel(false)) {

subscribeFuture.onComplete((res, e) -> {

if (e == null) {

this.unsubscribe(subscribeFuture, threadId);

}

});

}

this.acquireFailed(waitTime, unit, threadId);

return false;

} else {

//收到锁释放消息,准备重新发起请求

try {

//再次计算剩余时间

time -= System.currentTimeMillis() - current;

if (time <= 0L) {

//时间小于0 返回获取锁失败

this.acquireFailed(waitTime, unit, threadId);

boolean var20 = false;

return var20;

} else {

//准备发起请求

boolean var16;

do {

long currentTime = System.currentTimeMillis();

ttl = this.tryAcquire(waitTime, leaseTime, unit, threadId);

if (ttl == null) {

//获取锁成功

var16 = true;

return var16;

}

//再次计算剩余时间

time -= System.currentTimeMillis() - currentTime;

if (time <= 0L) {

//剩余时间为0 返回错误

this.acquireFailed(waitTime, unit, threadId);

var16 = false;

return var16;

}

currentTime = System.currentTimeMillis();

//判断key值剩余存活时间与当前time剩余时间 ,然后根据信号量的方案,在释放锁释放信号的时候发起请求

//注:有最大尝试时间,

//如果ttl即key值存活时间较少则最大尝试时间为锁的剩余存活时间

//如果time时间较少,则最大尝试时间为time

//第一种情况ttl较少 当ttl过期证明key已过期,没有再尝试的必要

//第二种情况time较少 证明已经超过重试时间,应该返回失败

//通过信号量的方式阻塞锁定当前,直至以获取到锁的线程释放锁,接收到信息后再继续向下执行代码

if (ttl >= 0L && ttl < time) {

((RedissonLockEntry)subscribeFuture.getNow()).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);

} else {

((RedissonLockEntry)subscribeFuture.getNow()).getLatch().tryAcquire(time, TimeUnit.MILLISECONDS);

}

//计算消耗时间

//如果是因为锁释放了,证明还有剩余时间,进行判断 ,剩余时间内再次发起获取锁的请求

time -= System.currentTimeMillis() - currentTime;

} while(time > 0L);

this.acquireFailed(waitTime, unit, threadId);

var16 = false;

return var16;

}

} finally {

this.unsubscribe(subscribeFuture, threadId);

}

}

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值