1.获取一把锁
RLock lock = redissonClient.getLock("订单lock");
2.业务代码加锁
lock.lock();
2.1 lock.tryAcquire
Long ttl = tryAcquire(leaseTime, unit, threadId);
2.2 tryAcquireAsync
1、调用tryLockInnerAsync
方法,执行的是一个lua脚本,如果获取锁失败,返回的结果是这个key的剩余有效期,如果获取锁成功,则返回null。
2、如果获取锁成功ttlRemaining == null
,并且leaseTime
是默认值-1时,则执行scheduleExpirationRenewal(threadId);
来启动看门狗机制
2.3 lua脚本: tryLockInnerAsync方法
如果获取锁失败,返回的结果是这个key的剩余有效期,如果获取锁成功,则返回null
getName="订单lock"
getLockName(threadId) = "abb26a86-01bb-4cc1-945c-d274ae2fd454:70" --->UUID:threadId
redis.exists:命令被用来检查键是否存在 | 若 key 存在返回 1 ,否则返回 0 |
redis.hset myhash field value 为哈希表中的field字段赋值 | |
redis.pexpire 命令用于设置键(key)的有效期限(以毫秒为单位) | 设置成功,返回 1 key 不存在或设置失败,返回 0 |
redis.hexists 命令用于查看哈希表的指定字段是否存在 | 1:包含字段; 0:不包含字段或键不存在 |
redis.hincrby myhash field 1 | 字段的增值操作后的值 |
redis.pttl 命令以毫秒为单位返回 key 的剩余过期时间 |
2.4 scheduleExpirationRenewal
2.4.1一个锁就对应自己的一个ExpirationEntry
类,EXPIRATION_RENEWAL_MAP
存放所有的锁信息
2.4.2 EXPIRATION_RENEWAL_MAP
里面获取锁,如果存在,则锁重入,如果不存在,则将新锁放入
getEntryName() = UUID+lockName ---> abb26a86-01bb-4cc1-945c-d274ae2fd454:订单lock
2.5 renewExpiration 方法异步更新锁的过期时间
1)从 EXPIRATION_RENEWAL_MAP 中获取与当前锁关联的 ExpirationEntry 对象。
2)如果未找到该对象,则直接返回。
3)使用 newTimeout 创建了一个定时任务
3.看门狗锁续期
renewExpirationAsync
1) 检查锁是否仍然存在,如果存在,则更新锁的过期时间为 internalLockLeaseTime
,返回1表示成功;
2)如果不存在,则返回0表示失败
4.解锁
lock.unlock();
- 如果释放锁过程中出现了异常,将异常抛出。
- 如果释放锁的操作状态为 null,抛出 IllegalMonitorStateException 异常,表示尝试释放一个未被当前线程持有的锁。
- 如果一切正常,则返回 null
4.1 解锁 -- unlockInnerAsync
4.2 移除锁 --- cancelExpirationRenewal
- 从
EXPIRATION_RENEWAL_MAP
中获取与锁关联的ExpirationEntry
对象。 - 如果未找到该对象,直接返回。
- 如果传入了
threadId
,则移除该线程 ID。 - 如果
threadId
为 null,或者锁不再被任何线程持有,则取消定时任务,并从EXPIRATION_RENEWAL_MAP
中移除该锁的相关信息