当前位置: 首页 > ops >正文

聊聊redisson的RLock的unlock

本文主要研究一下redisson的RLock的unlock

RLock

org/redisson/api/RLock.java

/*** Redis based implementation of {@link java.util.concurrent.locks.Lock}* Implements re-entrant lock.** @author Nikita Koksharov**/
public interface RLock extends Lock, RLockAsync {/*** Returns name of object** @return name - name of object*/String getName();/*** Acquires the lock with defined <code>leaseTime</code>.* Waits if necessary until lock became available.** Lock will be released automatically after defined <code>leaseTime</code> interval.** @param leaseTime the maximum time to hold the lock after it's acquisition,*        if it hasn't already been released by invoking <code>unlock</code>.*        If leaseTime is -1, hold the lock until explicitly unlocked.* @param unit the time unit* @throws InterruptedException - if the thread is interrupted*/void lockInterruptibly(long leaseTime, TimeUnit unit) throws InterruptedException;/*** Tries to acquire the lock with defined <code>leaseTime</code>.* Waits up to defined <code>waitTime</code> if necessary until the lock became available.** Lock will be released automatically after defined <code>leaseTime</code> interval.** @param waitTime the maximum time to acquire the lock* @param leaseTime lease time* @param unit time unit* @return <code>true</code> if lock is successfully acquired,*          otherwise <code>false</code> if lock is already set.* @throws InterruptedException - if the thread is interrupted*/boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException;/*** Acquires the lock with defined <code>leaseTime</code>.* Waits if necessary until lock became available.** Lock will be released automatically after defined <code>leaseTime</code> interval.** @param leaseTime the maximum time to hold the lock after it's acquisition,*        if it hasn't already been released by invoking <code>unlock</code>.*        If leaseTime is -1, hold the lock until explicitly unlocked.* @param unit the time unit**/void lock(long leaseTime, TimeUnit unit);/*** Unlocks the lock independently of its state** @return <code>true</code> if lock existed and now unlocked*          otherwise <code>false</code>*/boolean forceUnlock();/*** Checks if the lock locked by any thread** @return <code>true</code> if locked otherwise <code>false</code>*/boolean isLocked();/*** Checks if the lock is held by thread with defined <code>threadId</code>** @param threadId Thread ID of locking thread* @return <code>true</code> if held by thread with given id*          otherwise <code>false</code>*/boolean isHeldByThread(long threadId);/*** Checks if this lock is held by the current thread** @return <code>true</code> if held by current thread* otherwise <code>false</code>*/boolean isHeldByCurrentThread();/*** Number of holds on this lock by the current thread** @return holds or <code>0</code> if this lock is not held by current thread*/int getHoldCount();/*** Remaining time to live of the lock** @return time in milliseconds*          -2 if the lock does not exist.*          -1 if the lock exists but has no associated expire.*/long remainTimeToLive();}

RLock接口继承了JDK的java.util.concurrent.locks.Lock接口,同时还扩展提供了isLocked、isHeldByThread、isHeldByCurrentThread等方法

RedissonLock

org/redisson/RedissonLock.java

public class RedissonLock extends RedissonBaseLock {//......public void unlock() {try {get(unlockAsync(Thread.currentThread().getId()));} catch (RedisException e) {if (e.getCause() instanceof IllegalMonitorStateException) {throw (IllegalMonitorStateException) e.getCause();} else {throw e;}}//        Future<Void> future = unlockAsync();
//        future.awaitUninterruptibly();
//        if (future.isSuccess()) {
//            return;
//        }
//        if (future.cause() instanceof IllegalMonitorStateException) {
//            throw (IllegalMonitorStateException)future.cause();
//        }
//        throw commandExecutor.convertException(future);}//......
}    

RedissonLock继承了RedissonBaseLock,其unlock方法调用的是父类的unlockAsync,传递的参数为Thread.currentThread().getId()

unlockAsync

org/redisson/RedissonBaseLock.java

public abstract class RedissonBaseLock extends RedissonExpirable implements RLock {//......@Overridepublic RFuture<Void> unlockAsync() {long threadId = Thread.currentThread().getId();return unlockAsync(threadId);}@Overridepublic RFuture<Void> unlockAsync(long threadId) {RPromise<Void> result = new RedissonPromise<>();RFuture<Boolean> future = unlockInnerAsync(threadId);future.onComplete((opStatus, e) -> {cancelExpirationRenewal(threadId);if (e != null) {result.tryFailure(e);return;}if (opStatus == null) {IllegalMonitorStateException cause = new IllegalMonitorStateException("attempt to unlock lock, not locked by current thread by node id: "+ id + " thread-id: " + threadId);result.tryFailure(cause);return;}result.trySuccess(null);});return result;}//......
}

unlockAsync执行的是unlockInnerAsync,参数为当前thread的id,再其完成之后触发cancelExpirationRenewal

unlockInnerAsync

org/redisson/RedissonLock.java

    protected RFuture<Boolean> unlockInnerAsync(long threadId) {return evalWriteAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,"if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then " +"return nil;" +"end; " +"local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); " +"if (counter > 0) then " +"redis.call('pexpire', KEYS[1], ARGV[2]); " +"return 0; " +"else " +"redis.call('del', KEYS[1]); " +"redis.call('publish', KEYS[2], ARGV[1]); " +"return 1; " +"end; " +"return nil;",Arrays.asList(getRawName(), getChannelName()), LockPubSub.UNLOCK_MESSAGE, internalLockLeaseTime, getLockName(threadId));}

RedissonLock提供了unlockInnerAsync方法,执行的是一段lua脚本:

if redis.call('hexists', KEYS[1], ARGV[3]) == 0 thenreturn nil
endlocal counter = redis.call('hincrby', KEYS[1], ARGV[3], -1)if counter > 0 thenredis.call('pexpire', KEYS[1], ARGV[2])return 0
elseredis.call('del', KEYS[1])redis.call('publish', KEYS[2], ARGV[1])return 1
endreturn nil

先判断当前hash结构指定getLockName(threadId)的元素是否存在,不存在直接返回nil;接着对该线程的count减1,之后判断,若大于0则使用pexpire执行过期返回0;否则执行del命令,然后publish发送LockPubSub.UNLOCK_MESSAGE通知,返回1

isLocked

org/redisson/RedissonBaseLock.java

public abstract class RedissonBaseLock extends RedissonExpirable implements RLock {//......@Overridepublic boolean isLocked() {return isExists();}//......
}

isLocked方法是执行父类的isExists方法

    @Overridepublic boolean isExists() {return get(isExistsAsync());}@Overridepublic RFuture<Boolean> isExistsAsync() {return commandExecutor.readAsync(getRawName(), StringCodec.INSTANCE, RedisCommands.EXISTS, getRawName());}

通过exists命令来判断,参数为getRawName

isHeldByCurrentThread

org/redisson/RedissonBaseLock.java

    @Overridepublic boolean isHeldByCurrentThread() {return isHeldByThread(Thread.currentThread().getId());}@Overridepublic boolean isHeldByThread(long threadId) {RFuture<Boolean> future = commandExecutor.writeAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.HEXISTS, getRawName(), getLockName(threadId));return get(future);}

isHeldByCurrentThread调用的是isHeldByThread方法,传递的是Thread.currentThread().getId();isHeldByThread执行的是hexist命令,参数是getRawName()及getLockName(threadId)

小结

redisson的RLock接口继承了JDK的java.util.concurrent.locks.Lock接口,同时还扩展提供了isLocked、isHeldByThread、isHeldByCurrentThread等方法。

  • 其中unlock的时候先判断当前hash结构指定getLockName(threadId)的元素是否存在,不存在直接返回nil;接着对该线程的count减1,之后判断,若大于0则使用pexpire执行过期返回0;否则执行del命令,然后publish发送LockPubSub.UNLOCK_MESSAGE通知,返回1;
  • isLocked通过exists命令来判断,参数为getRawName()
  • isHeldByThread执行的是hexist命令,参数是getRawName()及getLockName(threadId)

doc

  • locks-and-synchronizers
http://www.xdnf.cn/news/6503.html

相关文章:

  • Java微服务架构实战:Spring Boot与Spring Cloud的完美结合
  • Linux 内核中 inet_accept 的实现与自定义传输协议优化
  • 在哪一个终端下运行有影响吗?pip install pillow
  • eVTOL、无人机电机功耗图和电机效率图绘制测试
  • Mendix 中的XPath 令牌(XPath Tokens)详解
  • 低空态势感知:基于AI的DAA技术是低空飞行的重要安全保障-机载端地面端
  • C++ Lambda 表达式介绍
  • 人工智能100问☞第24问:什么是生成对抗网络(GAN)?
  • 互联网应用的安全防线-身份证实名认证api-身份证三要素验证
  • BUUCTF——web刷题第一页题解
  • 【Java实战】IO流(转换流,打印流,数据流,序列化流)
  • Java随机生成邀请码 (包含字母大小写+数字)
  • 2022 Hubei Provincial Collegiate Programming Contest
  • 栈的计算方式和表达方式
  • 【深度剖析】安踏体育的数字化转型(上篇1)
  • 3D曲面上的TSP问题(二):ACO蚁群算法 + 2-opt搜索求解TSP问题
  • 讯联云库项目开发技术栈总结(一)
  • Linux系统发布.net core程序
  • 电脑自带画图工具,提取颜色
  • 软件工程之软件产品的环境
  • P1260 工程规划
  • 记录算法笔记(2025.5.15)二叉树的层序遍历
  • RK3588 桌面系统配置WiFi和蓝牙配置
  • SQL优化总结
  • vue使用vite, 渲染glb模型时报错
  • 【GESP真题解析】第 9 集 GESP 一级 2023 年 9 月编程题 2:小明的幸运数
  • 检测按键抖动的时间
  • ivx 开发者如何通过 BI 引擎实现应用功能精准优化
  • 深光-谷歌TV TADA/奈飞Netflix/亚马逊Prime Video/YouTube等测试外包服务
  • 【蓝桥杯嵌入式】【模块】四、按键相关配置及代码模板