实现思路
实现的分布式锁的最常见方式是使用redis分布式锁(redis分布式锁参考我的专栏——分布式锁),基本原理是在各个服务执行到临界区(造作共享资源的代码块)之前,去redis中尝试添加一个带有当前贡献资源标识的redis数据,如果redis中没有该键值,添加成功,代表加锁成功,如果redis中已经存在该键值,添加失败,则加锁失败。
而zookeeper的原理就完全不一样了:
- 首先,每个客户端会去某个指定的znode(一般情况,一类分布式锁都创建在某一个node path下)下创建临时有序节点,所以每个客户端创建出来的临时节点都会按照序列分配序号如/locks/lock_000000001、/locks/lock_000000002、/locks/lock_000000003.......
- 客户端获取到/lock下的子节点,并进行排序,判断排在最前面的节点是否是自己创建的节点,如果是,那么就获取到锁。
- 如果自己创建的节点并不在第一个,则监听前一个节点
- 前一个节点的客户端执行完毕,释放锁之后,就会触发监听,通知到下一个节点的客户端
- 监听客户端重新执行第2步动作,尝试获取锁
基本实现
本文的demo示例仅作为zookeeper分布式锁的原理分析示例!!!
引入zookeeper自带Java客户端
-
<dependency>
-
<groupId>org.apache.zookeeper
</groupId>
-
<artifactId>zookeeper
</artifactId>
-
<version>3.7.0
</version>
-
</dependency>
编写示例
-
package org.leolee.zookeeper.distributedLock;
-
-
import org.apache.zookeeper.*;
-
import org.apache.zookeeper.data.Stat;
-
-
import java.io.IOException;
-
import java.util.Collections;
-
import java.util.List;
-
import java.util.concurrent.CountDownLatch;
-
-
/**
-
* @ClassName MyLock
-
* @Description: 分布式锁
-
* @Author LeoLee
-
* @Date 2021/4/14
-
* @Version V1.0
-
**/
-
public
class MyLock {
-
-
private
static
final String IP =
"127.0.0.1:2181";
-
-
CountDownLatch countDownLatch =
new CountDownLatch(
1);
-
-
ZooKeeper zooKeeper;
-
-
private
static
final String LOCK_ROOT_PATH =
"/locks";
-
-
private
static
final String LOCK_NODE_NAME =
"lock_";
-
-
private String lockPath;
-
-
//连接zookeeper
-
public MyLock() {
-
try {
-
zooKeeper =
new ZooKeeper(IP,
5000,
new Watcher() {
-
@Override
-
public void process(WatchedEvent watchedEvent) {
-
if (watchedEvent.getState().equals(Event.KeeperState.SyncConnected)) {
-
System.out.println(
"connect success");
-
countDownLatch.countDown();
-
}
else
if (watchedEvent.getState().equals(Event.KeeperState.Disconnected)) {
-
System.out.println(
"connection break");
-
}
else
if (watchedEvent.getState().equals(Event.KeeperState.Expired)) {
-
System.out.println(
"session timeout");
-
}
else
if (watchedEvent.getState().equals(Event.KeeperState.AuthFailed)) {
-
System.out.println(
"auth failed");
-
}
-
}
-
});
-
countDownLatch.await();
-
}
catch (IOException e) {
-
e.printStackTrace();
-
}
catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
}
-
-
Watcher watcher =
new Watcher() {
-
@Override
-
public void process(WatchedEvent watchedEvent) {
-
//监视的前一个节点被删掉后通知
-
if (watchedEvent.getType().equals(Event.EventType.NodeDeleted)) {
-
synchronized (watcher) {
-
watcher.notifyAll();
-
}
-
}
-
}
-
};
-
-
/**
-
* 功能描述: <br>
-
* 〈〉获取锁
-
* @Param: []
-
* @Return: void
-
* @Author: LeoLee
-
* @Date: 2021/4/14 23:00
-
*/
-
public void acquireLock() throws KeeperException, InterruptedException {
-
createLock();
-
tryLock();
-
}
-
-
private void createLock() throws KeeperException, InterruptedException {
-
//判断锁根节点是否存在
-
Stat stat = zooKeeper.exists(LOCK_ROOT_PATH,
false);
-
if (stat ==
null) {
-
zooKeeper.create(LOCK_ROOT_PATH,
new
byte[
0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
-
}
-
//创建锁节点(临时有效节点)
-
lockPath = zooKeeper.create(LOCK_ROOT_PATH +
"/" + LOCK_NODE_NAME,
new
byte[
0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
-
System.out.println(
"lock node create success, lock path:" + lockPath);
-
}
-
-
private void tryLock() throws KeeperException, InterruptedException {
-
List<String> children = zooKeeper.getChildren(LOCK_ROOT_PATH,
false);
-
//对子节点进行排序
-
Collections.sort(children);
-
int index = children.indexOf(lockPath.substring(LOCK_ROOT_PATH.length() +
1));
-
if (index ==
0) {
-
System.out.println(
"try lock success");
-
return;
-
}
else {
-
//获取上一个节点
-
String preNode = children.get(index -
1);
-
//对上一个节点进行watch
-
Stat preNodeStat = zooKeeper.exists(LOCK_ROOT_PATH +
"/" + preNode, watcher);
-
if (preNodeStat ==
null) {
-
acquireLock();
-
}
else {
-
synchronized (watcher) {
-
watcher.wait();
-
}
-
}
-
}
-
}
-
-
/**
-
* 功能描述: <br>
-
* 〈〉释放锁
-
* @Param: []
-
* @Return: void
-
* @Author: LeoLee
-
* @Date: 2021/4/14 23:01
-
*/
-
public void releaseLock() throws KeeperException, InterruptedException {
-
//删除临时有序节点
-
zooKeeper.delete(lockPath, -
1);
-
System.out.println(
"lock release");
-
zooKeeper.close();
-
}
-
}
转载:https://blog.csdn.net/qq_25805331/article/details/115705694
查看评论