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

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

151次阅读
没有评论

共计 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字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)
主站蜘蛛池模板: 国产在线观看一区二区三区 | 91精品啪在线观看国产线免费 | 亚洲精品一线二线三线无人区 | 成人不卡 | 美女张开腿让男生桶出水 | 99精品国产一区二区三区不卡 | 国产精品久久久久久免费播放 | 亚洲se主站| yellow视频在线免费观看 | 亚洲综合偷自成人网第页色 | 丰满熟女人妻一区二区三 | 亚洲日韩中文无码久久 | 国产精品秋霞午夜 | 欧洲变态另类zozo | 99精品全国免费观看视频 | 老子影院午夜理伦手机 | 少妇人妻互换不带套 | 伊人久综合 | 天天干天天操天天做 | 公么看我喂奶水涨帮我吃小说 | 99久久影视 | 免费无码高h视频在线观看 免费无码高潮流白浆视频 免费无码国产v片在线观看 | 麻豆精品久久久 | 玖玖在线资源站 | 我要看黄色一级片 | 国产草草视频 | 久久精品国产精品亚洲婷婷 | 国产精品特级毛片一区二区三区 | 国产韩国精品一区二区三区 | 国产精品1区2区3区在线播放 | 成人福利视频在线观 | 亚洲人成无码网站 | 日本三级电影免费看 | 伊人网欧美 | 国产成人无码国产亚洲 | 色综综| 中文精品久久久久中文 | 天堂av无码av一区二区三区 | 亚洲综合一区二区三区四区 | 亚洲成av人片天堂网 | 午夜视频在线观看视频 |