目录
文字有点多,也可以直接进入图解过程
一、引入问题
单进程jvm下,可以用java内置锁和显示锁来确保线程安全。但是在多jvm下时,如何保证线程安全呢,java层级已经解决不了这个问题。也就是说不同的jvm如何保证资源安全性?引出ZK解决分布式带来的资源同步问题
二、了解ZK
理解节点,为实现分布式锁铺垫。
ZK有四种节点
1、持久节点
默认的节点类型。创建节点的客户端与zookeeper断开连接后,该节点依旧存在。
2、持久节点顺序节点
在创建节点时,zookeeper根据创建的时间顺序给该节点名称进行编号
3、临时节点
和持久节点相反,当创建节点的客户端与zookeeper断开连接后,临时节点会被删除
4、临时顺序节点
在创建节点时,zookeeper根据创建的时间顺序给该节点名称进行编号排序(排序的节点形成一个类似队列)。当创建节点的客户端与zookeeper断开连接后,临时节点会被删除(解锁)
三、ZK实现分布式锁过程
这里我以三个不同的客户端client1、client2、client3来演示ZK实现分布式锁的过程。
1、首先,在ZK创建一个持久节点ParentLock。当第一个客户端想要获得锁时,需要在ParentLock这个节点下面创建一个临时顺序的节点(临时节点1),client1查找ParentLock下面所有的临时顺序节点并排序,判断自己所创建的节点(临时节点1)是不是顺序最靠前的一个。如果是则成功获得锁。执行同步代码块。
2、这个时候,如果再有一个客户端client2(可以理解成不同的进程)前来获取锁,则ParentLock下再创建一个临时顺序节点(临时节点2)。client2查找ParentLock下面所有的临时顺序节点并排序,判断自己所创建的节点(临时节点2)是不是顺序最靠前的一个,发现不是最小,于是,client2向前排序仅比它靠前的节点注册Watcher,用来监听--临时节点1是否存在。这意味着client2抢锁失败。
3、这个时候,又有一个客户端client3前来获取锁,则ParentLock下再创建一个临时顺序节点(临时节点3)。client3查找ParentLock下面所有的临时顺序节点并排序,判断自己所创建的节点(临时节点3)是不是顺序最靠前的一个,发现不是最小,于是,client3向前排序仅比它靠前的节点注册Watcher,用来监听--临时节点2是否存在。这意味着client3抢锁失败。
4、客户端client1执行完同步代码块,断开与zookeeper连接,对应的临时节点1也会被删除,解锁成功。此时client2监听到临时节点1不存在,于是拿到锁。执行同步代码块。
5、客户端client2执行完同步代码块,断开与zookeeper连接,对应的临时节点2也会被删除,解锁成功。此时client3监听到临时节点2不存在,于是拿到锁。执行同步代码块。
6、客户端client3执行完同步代码块,断开与zookeeper连接,对应的临时节点3也会被删除,解锁成功。
四、图解ZK实现分布式锁过程
1、client1拿锁解释过程,不涉及分布式锁
2、这里我以三个不同的客户端client1、client2、client3来演示ZK实现分布式锁的过程。
1.client1拿锁,创建临时节点1并排序,临时节点1在第一位,成功拿锁==执行同步代码块
2.client2拿锁,创建临时节点2并排序,临时节点2不在第一位,创建监听器监听前面一个临时节点1,拿锁失败==监听中
3.client3拿锁,创建临时节点3并排序,临时节点3不在第一位,创建监听器监听前面一个临时节点2,拿锁失败==监听中。
此时client2也在监听着临时节点1
4.client1同步代码执行完毕断开与zookeeper连接,删除临时节点1,相当于释放锁。
client2一直监听着临时节点1,发现其不存在,拿锁成功==执行同步代码块
client3继续监听
5.client2同步代码执行完毕断开与zookeeper连接,删除临时节点2,相当于释放锁。
client3一直监听着临时节点2,发现其不存在,拿锁成功==执行同步代码块
6.client3同步代码执行完毕断开与zookeeper连接,删除临时节点3,相当于释放锁。