万剑归宗之七剑下天山,redisson的百锁解构(下)

上文,我们分析了redisson剑谱里面的前四式,参见【万剑归宗,redisson的百锁解构(上) 】,本文将继续解构后面的四个招式,对于这些招式的拆解,除了可以让我们对redisson知其然知其所以然,也可以帮助我们去理解jdk中本身就已经实现的那些锁。继续演练余下的几招,以指为剑,剑破苍穹。

【 招式四  读写锁 】

读写锁,在很多业务场景中,读多写少,多个客户端可以同时读,但是有人写的时候不能读,这个时候读写锁就是最佳选择了,自然是要分为读锁,写锁,而且肯定都是要单独加锁的,这其中就涉及了锁互斥的机制,读读,读写,写写,写读,这些情况都是怎么处理的呢?OK,我们从源码入手,见招拆招。

【 读锁&加锁】

读锁的加锁逻辑,也是在lua脚本中的,这段脚本也不长,首先呢他是根据

锁key的hash结构中去hget一个mode的值,这个mode的值要么是读read,要么是写write,我们第一次来加读锁,那肯定就是不存在的,就进入分支进行加锁,加锁的逻辑很简单,把mode设置为read,设置37f75873-494a-439c-a0ed-f102bc2f3204:1,值为1,设置{anyLock}:37f75873-494a-439c-a0ed-f102bc2f3204:1:rwlock_timeout:1,

值为1,并且将上面俩个俩个值的有效期设置为30000毫秒,就返回nil啦,加锁成功。

【 读锁&读读&读写 】

那么读读会互斥吗?从上面的源码中我们可以看出来,并不会,如果已经有一个客户端已经加锁了,那么此时的mode还是read,会进入到判断分支,hincrby自增新的锁key [ID:threadId],这里这么做,有俩个好处,如果是同一个客户端同一个线程,就会自增1,如果不是的话,就会新增一个kv,[ID2:threadId2],也会和之前一样拼接一个rwlock_timeout的kv,,并且给所有的key设置有效期为30000毫秒。到这里,很清晰了,读锁的读读是不会互斥的。

那么读写会互斥吗?假设我们已经加了一把读锁,此时有人过来加写锁呢?这样,我们先来分析分析写锁的加锁机制,再来回答这个问题。【结论:读读不互斥,读写互斥

【 写锁&加锁 】

写锁的逻辑是怎样的呢?

首先还是先获取了当前的mode是什么,我们先假设第一次加写锁,此时还是直接进入分支,设置模式为write,设置[ID:threadId1:write]为1,最后再将锁key的有效期设置为30000毫秒;好啦,这里我们来看看,读写是否互斥,此时假设已经有人加了读锁,此时来加写锁,直接就是闭门羹,返回了ttl的剩余有效期,那么客户端就会进入循环去尝试获取锁,【结论:读写是互斥的

【 写锁&写读 】

当一个客户端已经加了写锁之后,这个时候新的客户端来加读锁,这里就要看情况了,因为看代码中会有所区分,如果是当前持有写锁的客户端的当前线程来加读锁,是没问题的,如果不是,就直接返回剩余时间,一直循环等待加锁了,【结论:写读看情况,如果是持有写锁的客户端线程加读锁,ok,否则互斥

【 写锁&写写 】

如果是写写呢?此时已经有用户加了写锁,这时,一个新客户端来尝试加写锁,此时也会进行判断,如果是当前持有写锁的客户端线程,那么就会进入分支,也是操作一些自增,延长时间的操作,如果不是呢,就会返回剩余时间,进入等待循环尝试加锁了。【结论:写写互斥,但是可重入

【 读锁&watchdog机制&可重入 

redisson一般加锁的watchdog机制我们都已经分析过了,请看【汪~汪~汪~redisson的WatchDog是如何看家护院的? 】,而读锁的watchdog有一些特殊的逻辑,这里我们也来看看,首先显示获取了这个锁key对应的hash结构中是否存在加锁,如果存在,就会先将锁key的有效期延长为30000毫秒,接着hlen查看hash结构中数量,如果大于1就进入分支,获取所有key,并且进行遍历,获取到值为number的key,其实就是为了拼接得出{anyLock}:37f75873-494a-439c-a0ed-f102bc2f3204:1:rwlock_timeout:1

所有这样的key,并且将这些可以的时间都延长,这里我们也可以看出来,读锁是可重入的,然后就返回继续定时续期锁key的有效期。

读锁 &释放

接下来我们继续看看读锁的释放逻辑,这个脚本略长,我们来细细分析一波:释放逻辑呢,主要分成几种情况,我们一一来看。

首先,如果mode值不存在那么也就直接返回1了,先判断一波当前客户端线程是否存在加读锁,如果不存在,说明有问题,返回nil;接下来也说明了读锁存在,先对读锁的值-1,返回了当前的counter值,如果等于0,就直接把锁key删除hdel,紧接着我们就去删除rwlock_timeout对应的(counter+1)key删除;接下来还是去判断hash机构中的key的数量,

情况1:如果大于1,去遍历所有的key,遍历所有的rwlock_timeout,并且pttl获取他们的剩余时间,并且拿到了这些key值中最大的有效期时间maxRemainTime,如果大于0,就将锁key的有效期设置为maxRemainTime,并且返回0 ,这时候释放锁不成功。如果是写模式呢,直接返回0;

情况2:如果小于1,就直接删除锁key,释放锁成功。

对于读锁的释放,因为存在可重入性,所以逻辑上要进行循环判断,只有全部都释放了,读锁才会真正释放了。

【 写锁&释放锁 】

写锁的释放,写锁也是存在可重入的,当model是write的时候,

先判断当前线程的写锁是否存在,如果不存在,返回nil;否则,也是先对写锁值-1,如果值大于0,就返回0,释放锁不成功;否则,就开始进行删除操作,将写锁对应的值都删除,还有个小细节,这里回去判断hlen key的个数,如果等于1,说明没有客户端持有锁,删除锁key,否则说明有读锁持有,就要将mode模式转为read;返回1,释放锁成功。

招式五 信号量

信号量,Semaphore,这种锁机制很特殊,在很多特殊场景也会得到运用,他可以指定允许获取锁的线程个数,允许指定数量的多个客户端线程获取同一把锁,一旦其中某个线程释放了,其他线程也可以获得这把锁。他的实现原理是怎么样的呢?

我们在使用api加锁的时候会传入permits,允许加锁的客户端线程个数,这里加锁的逻辑并不复杂,第一次加锁,判断当前key对应的数量【value】和【permits=1】的大小,如果大于直接进入分支,对当前锁key的值-1,返回1,加锁成功,可以想象,一旦经过多次-1,value=0的时候,0>=1不成立,就会返回0,这个客户端线程就需要循环等待尝试加锁了。

释放锁的逻辑更简单,每次释放锁,就对锁key的value进行+1,这样子,新的客户端加锁就能获取成功。so easy~~

【招式六 CountDownLatch 闭锁】

这也是一把好玩的锁,使用此锁,需要指定数量的客户端线程都加锁,否则其他加锁的线程会阻塞住,直到所有的客户端都加锁成功才会进行往下的逻辑,什么样的场景适用呢,如果我们某个业务操作需要多个步骤都完成才能进行下一个步骤,那么就可以用这个锁啦,直接锁住,等待所有任务完成,释放锁之后,就可以进行下一步操作了

那么他是怎么实现的呢?

首先肯定是设置数量trySetCount(count),很简单,就是对key设置了

数量n,紧接着就需要n个线程去操作countdown(),这其中的逻辑也很简单,就是每次操作就会将key的值-1,直到key的值为0的时候,就会删除掉这个key,

而其他地方会有一个操作,就是await(),他会不断循环获取key的值,直到值等于0才会往下操作,是不是很简单,就实现了这一机制。

【 招式七 可重入非公平锁 】

可重入非公平锁的机制我们在前面的篇文章中已经讲解过了,参见【扒开Redisson的小棉袄,Debug深入剖析分布式锁之可重入锁No.1】,回顾一下吧。

对于redisson分布式锁框架的解构到这里就差不多了,是不是觉得简单一招一式,也成就了分布式锁凌厉的剑气,对于上下俩篇的解构,其中涉及了七种分布式锁的机制,若文中有描述错误的,欢迎小伙伴指正批评,悉心接受。谢谢大家观看。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容