Redisson的分布式锁是基于redis的,curator的分布式锁是基于zookeeper的。
curator的分布式锁在zookeeper之分布式锁曾经解说过了,这篇不讲源码的具体实现,讲讲他们实现分布式锁的流程。

Redisson的分布式锁

假如当初有某个服务的线程A,向Redis申请锁。他须要提供这个锁的名称(假如lock)、本人的信息(假如Thread-A)以及key生效的工夫(假如30s,如果没有设置生效工夫,当线程A异样退出,这个key会始终保留在Redis中,那其余线程申请锁的时候,会始终阻塞导致申请不到锁)。

向Redis申请锁的时候,线程A会发送Lua脚本给Redis。

因为思考到锁的可重入,所以这个数据结构是哈希,key对应的值是锁的名称,哈希是锁的持有者和拿到锁的数值。

Redis收到申请后,就会判断是否有这个key,因为线程A是第一次申请这个key的,所以很显著没有,于是就创立新的哈希表,设置对应的数值和过期工夫。

如果线程A再申请lock这个锁,Redis此时曾经有了这个key,所以他就会看看这个key的持有者是不是以后申请者,此时以后持有者就是线程A,所以就会把数值加1,从1变成了2,而后再重置过期工夫。

咱们下面设置了30s的过期工夫,如果程序执行了30s,还没执行完,就过期了,那这个锁就生效了,其余线程就会拿到锁,导致互斥性生效,所以Redisson有一个监听狗的机制。

咱们的过期工夫是30s,那监听狗(其实就是开启了一个线程)每30s/3=10s会给Redis发送申请,如果这个key的持有者是以后线程,那就会把生效工夫重置为30s。

在线程A持有锁的时候,线程B也来申请锁。

因为这个key存在,且不是线程B持有的锁,所以他就获取锁失败了。

失败后他就会去订阅这个锁的解锁播送信息,并且创立信号量。

线程A开释锁的时候,会判断是否为以后锁的持有者,因为以后就是线程A,所以把数值从2减1,阐明还是线程A持有锁。

当线程A再开释锁的时候,这个数值就减为0,阐明线程A曾经不须要这个锁了,此时Redis就会公布这个锁的解锁播送。

线程B可是始终订阅这个锁的解锁播送,当A解锁后,线程B就会接管到这个订阅,所以就开释信号量。

过后开释信号量的时候,线程B就开始从新申请,流程同上,如果还是没有获取到锁,那就会持续订阅这个锁的播送信息,当然不是有限期待,获取锁的过期工夫到了,就阐明没有获取锁。

curator的分布式锁

同样假如当初有某个服务的线程A,向Zookeeper申请锁。他须要提供这个锁的门路,并要求Zookeeper生成一个长期有序节点。因为这个lock目前还没有创立过长期节点,所以假如这个长期有序节点是/lock/0001。Zookeeper创立后就会把这个门路返回给线程A。

线程A拿到门路后,还会去拿/lock下的所有节点(此时就/lock0001),并进行排序。

排序完看看以后的节点是不是第一个,因为目前就是第一个,所以线程A就相当于拿到了锁,把线程的信息、节点的门路保留在内存中,并默认lockCount的值为1。

如果线程A再申请锁,他就会先看看内存是否有以后线程和这个门路的信息,如果有,就把lockCount加1,此时lockCount就是2。

在线程A持有锁的时候,线程B也来申请锁。

因为这个lock曾经有了0001的长期有序节点,所以Zookeeper就会创立lock0002并返回给线程B。

线程B拿到门路后,同样会去拿/lock下的所有节点(此时就有/lock0001和/lock0002),并进行排序。

很显著他不是第一个节点,所以拿不到锁,于是就监听lock0001,并进入了wait。

线程A开释锁的时候,就会把内存中的lockCount减1,而后判断lockCount是否大于0,如果大于0,阐明之前重入过,还须要持有锁,如果小于0,阐明曾经开释完了,如果等于0,阐明不须要加锁了,那就移除监听,并删除长期有序节点。

Zookeeper删除lock0001时,Zookeeper的watch机制就会告诉到线程B,此时就会唤醒线程B,线程B会从新去Zookeeper拉取子节点列表,并排序,此时lock0002是第一个,所以他就获取到了锁,而后把线程的信息、节点的门路保留在内存中,并默认lockCount的值为1。

Zookeeper分布式锁的流程大略如上。

那为什么是长期节点?当线程A异样退出后,这个长期节点也会删除,这样就能够通过watch机制告诉监听这个节点的服务。

为什么是程序节点?长期节点也能够保障互斥性,然而这样就会很多个服务始终争着去创立这个节点。

所以Zookeeper的长期节点,能够不必像Redis一样,须要过期工夫防死锁,Watch机制不必像Redis一样,须要监听狗来放弃锁。

重入也有不一样的中央,Zookeeper是保留客户端,Redis是保留在Redis中。