在线精品99_中国九九盗摄偷拍偷看_91免费版在线观看_91.app_91高清视频在线_99热最新网站

Redis如何实现可重入锁的设计

133次阅读
没有评论

共计 3553 个字符,预计需要花费 9 分钟才能阅读完成。

自动写代码机器人,免费开通

这篇文章主要介绍 Redis 如何实现可重入锁的设计,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

但是仍然有些场景是不满?的,例如? 个?法获取到锁之后,可能在?法内调这个?法此时就获取不到锁了。这个时候我们就需要把锁改进成可 重?锁了。重?锁,指的是以线程为单位,当?个线程获取对象锁之后,这个线程可以再次获取本对象上的锁,?其 他的线程是不可以的。可重?锁的意义在于防?死锁。实现原理是通过为每个锁关联?个请求计数器和?个占有它的线程。当计数为 0 时,认为锁是未被占有 的;线程请求?个未被占有的锁时,JVM 将记录锁的占有者,并且将请求计数器置为 1。如果同?个线程再次请求这个锁,计数将递增;每次占?线程退出同步块,计数器值将递减。直到计数器 为 0, 锁被释放。关于?类和?类的锁的重?:?类覆写了?类的 synchonized ?法,然后调??类中的?法,此时如果没有重?的锁,那么这段代码将产?死锁。

代码演示

不可重?

不可重?锁
Redis 如何实现可重入锁的设计

使用不可重入锁 Redis 如何实现可重入锁的设计
当前线程执? call() ?法?先获取 lock,接下来执? inc() ?法就?法执? inc() 中的逻辑,必须先释放锁。该例很好的说明了不可重?锁。

可重入锁

锁实现
Redis 如何实现可重入锁的设计

锁使用 Redis 如何实现可重入锁的设计

可重?意味着线程可进?它已经拥有的锁的同步代码块。

设计两个线程调? call() ?法,第?个线程调? call() ?法获取锁,进? lock() ?法,由于初始 lockedBy 是 null,所以不会进? while ?挂起当前线程,?是增量 lockedCount 并记录 lockBy 为第 ?个线程。

接着第?个线程进? inc() ?法,由于同?进程,所以不会进? while ?挂起,接着增量 lockedCount,当第?个线程尝试 lock,由于 isLocked=true, 所以他不会获取该锁,直到第?个线程调?两次 unlock() 将 lockCount 递减为 0,才将标记为 isLocked 设置为 false。

设计思路

假设锁的 key 为“lock”,hashKey 是当前线程的 id:“threadId”,锁自动释放时间假设为 20。

获取锁

判断 lock 是否存在 EXISTS lock

不存在,则自己获取锁,记录重入层数为 1.

存在,说明有人获取锁了,继续判断是不是自己的锁,即判断当前线程 id 作为 hashKey 是否存在:HEXISTS lock threadId

不存在,说明锁已经有了,且不是自己获取的,锁获取失败.

存在,说明是自己获取的锁,重入次数 +1:HINCRBY lock threadId 1,最后更新锁自动释放时间,EXPIRE lock 20
Redis 如何实现可重入锁的设计

释放锁

判断当前线程 id 作为 hashKey 是否存在:HEXISTS lock threadId

不存在,说明锁已失效

存在,说明锁还在,重入次数减 1:HINCRBY lock threadId -1,

获取新的重入次数,判断重入次数是否为 0,为 0 说明锁全部释放,删除 key:DEL lock

因此,存储在锁中的信息就必须包含:key、线程标识、重入次数。不能再使用简单的 key-value 结构,这里推荐使用 hash 结构。而且要让所有指令都在同一个线程中操作,那么使用 lua 脚本。

lua 脚本

lock.lua

local key = KEYS[1]; --  第 1 个参数, 锁的 keylocal threadId = ARGV[1]; --  第 2 个参数, 线程唯一标识 local releaseTime = ARGV[2]; --  第 3 个参数, 锁的自动释放时间 if(redis.call( exists , key) == 0) then --  判断锁是否已存在
 redis.call( hset , key, threadId,  1  --  不存在,  则获取锁
 redis.call(expire , key, releaseTime); --  设置有效期
 return 1; --  返回结果 end;if(redis.call( hexists , key, threadId) == 1) then --  锁已经存在,判断 threadId 是否是自己  
 redis.call( hincrby , key, threadId,  1  --  如果是自己,则重入次数 +1
 redis.call(expire , key, releaseTime); --  设置有效期
 return 1; --  返回结果 end;return 0; --  代码走到这里, 说明获取锁的不是自己,获取锁失败 

unlock.lua

--  锁的  keylocal key = KEYS[1];--  线程唯一标识 local threadId = ARGV[1];--  判断当前锁是否还是被自己持有 if (redis.call( hexists , key, threadId) == 0) then--  如果已经不是自己,则直接返回
 return nil;end;--  是自己的锁,则重入次数减一 local count = redis.call(hincrby , key, threadId, -1);--  判断重入次数是否已为 0if (count == 0) then--  等于  0,说明可以释放锁,直接删除
 redis.call(del , key);
 return nil;end;

在项目中集成

编写 RedisLock 类

@Getter@Setterpublic class RedisLock {
 private RedisTemplate redisTemplate;
 private DefaultRedisScript Long  lockScript;
 private DefaultRedisScript Object  unlockScript;
 public RedisLock(RedisTemplate redisTemplate) {
 this.redisTemplate = redisTemplate;
 //  加载释放锁的脚本
 this.lockScript = new DefaultRedisScript ();
 this.lockScript.setScriptSource(new ResourceScriptSource(new ClassPathResource( lock.lua)));
 this.lockScript.setResultType(Long.class);
 //  加载释放锁的脚本
 this.unlockScript = new DefaultRedisScript ();
 this.unlockScript.setScriptSource(new ResourceScriptSource(new ClassPathResource( unlock.lua)));
 }
 /**
 *  获取锁
 * @param lockName  锁名称
 * @param releaseTime  超时时间 (单位: 秒)
 * @return key  解锁标识
 */
 public String tryLock(String lockName, long releaseTime) {
 //  存入的线程信息的前缀,防止与其它 JVM 中线程信息冲突
 String key = UUID.randomUUID().toString();
 //  执行脚本
 Long result = (Long)redisTemplate.execute(
 lockScript,
 Collections.singletonList(lockName),
 key + Thread.currentThread().getId(), releaseTime);
 //  判断结果
 if(result != null   result.intValue() == 1) {
 return key;
 }else {
 return null;
 }
 }
 /**
 *  释放锁
 * @param lockName  锁名称
 * @param key  解锁标识
 */
 public void unlock(String lockName, String key) {
 //  执行脚本
 redisTemplate.execute(
 unlockScript,
 Collections.singletonList(lockName),
 key + Thread.currentThread().getId(), null);
 }}

以上是“Redis 如何实现可重入锁的设计”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注丸趣 TV 行业资讯频道!

向 AI 问一下细节

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-12-04发表,共计3553字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)
主站蜘蛛池模板: 国产成人精品久久二区二区 | 成人免费无码大片a毛片软件 | 日本特级全黄一级毛片 | 三级国产4国语三级在线 | 日韩午夜 | 国产午夜三级一区二区三 | 国产在线视频第一页 | 欧美在线免费 | 亚洲一片 | 中文字幕网伦射乱中文 | 少数民族美乳国产在线 | 亚洲激情网站 | 日本一级片在线播放 | 日本三级电影免费看 | 尤物网站在线看 | 91精品国产高清久久久久久91 | 中国老太婆bb无套内射 | 伊人婷婷色香五月综合缴缴情小蛇 | 亚洲大尺度无码无码专线一区 | 国产精品久久久久影视青草 | 亚洲精品久久久成人 | 永久毛片 | 一区免费视频 | 九九热在线精品视频 | 国产精品一区二区免费 | 欧美内射深喉中文字幕 | 美国爱爱片视频在线观看 | 欧美一级人与动毛片免费播放 | 成年女性视频 | 韩国私人vps啪啪 | 香蕉521av网站永久地址 | 国产一级淫片a免费播放口之 | 青青青手机在线视频 | 国产精品久久久免费视频 | 免费国产成人高清视频网站 | 日本视频在线观看不卡高清免费 | 一级黄色在线看 | 丝袜 中出 制服 人妻 美腿 | 欧美性网址 | 久久久久久久久久福利 | 亚洲欧洲日本精品 |