分布式锁_Zookeeper分布式锁实践
环境说明
Ubuntu: 20.04
Zookeeper: 3.7.0
JDK: 1.8
Zookeeper
wget https://www.apache.org/dyn/closer.lua/zookeeper/zookeeper-3.7.0/apache-zookeeper-3.7.0-bin.tar.gz
tar xf apache-zookeeper-3.7.0-bin.tar.gz
mv apache-zookeeper-3.7.0-bin zookeeper
mv zookeeper/conf/zoo_sample.cfg zookeeper/conf/zoo.cfg
修改配置zoo.cfg
zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/tmp/zookeeper/data
clientPort=2181
JAVA开发
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.quange</groupId>
<artifactId>distributelock</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.7.0</version>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>
ZooKeeper分布式锁实现类
ZkDistributeLock.java
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
public class ZkDistributeLock implements DistributeLock, Watcher {
private ZooKeeper zooKeeper;
ThreadLocal<String> cache = new ThreadLocal<>();
public ZkDistributeLock() {
try {
zooKeeper = new ZooKeeper("localhost:2181", 30000, this);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public boolean lock(String resource) {
String parentPath = "/" + resource;
try {
//创建资源节点(父节点)
Stat stat = zooKeeper.exists(parentPath, false);
while(stat==null) {
try {
zooKeeper.create(parentPath, resource.getBytes(),
ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.CONTAINER);
} catch (Exception e) {
e.printStackTrace();
}
stat = zooKeeper.exists(parentPath, false);
}
//创建瞬时有序节点 /resource/resource_00000001
String nodePath = parentPath + "/" + resource + "_";
String znode = zooKeeper.create(nodePath, resource.getBytes(),
ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.EPHEMERAL_SEQUENTIAL);
cache.set(znode);
//获取资源节点下 所有的子节点
List<String> childrenNodes = zooKeeper.getChildren(parentPath, false);
//子节点排序
Collections.sort(childrenNodes);
//获取序号最小的(第一个)子节点
String firstNode = childrenNodes.get(0);
Log.d("znode="+ znode+" :firstNode="+firstNode + " " + znode.endsWith(firstNode));
//如果创建的节点是第一个子节点,则获得锁
if (znode.endsWith(firstNode)){
System.out.println("TRUE");
return true;
}
//不是第一个子节点,则监听前一个节点
String lastNode = firstNode;
for (String node:childrenNodes){
if (znode.endsWith(node)){
Log.d("watch " + lastNode);
zooKeeper.exists(parentPath+"/"+lastNode,true);
break;
} else {
lastNode = node;
}
}
synchronized (this){
wait();
}
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
@Override
public boolean unLock(String resource) {
try {
System.out.println(cache.get());
zooKeeper.delete(cache.get(),-1);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
@Override
public void process(WatchedEvent watchedEvent) {
if (watchedEvent.getType() == Event.EventType.NodeDeleted) {
Log.d(watchedEvent.getPath() + " - " + watchedEvent.getType());
synchronized (this){
notify();
}
}
}
}
其他不重要类
点击查看
public interface DistributeLock {
boolean lock(String resource);
boolean unLock(String resource);
}
public enum DistributeLockType {
DB,
REDIS,
ZOOKEEPER
}
public class DistributeLockFactory {
public static DistributeLock getDistributeLock() {
return new DbDistributeLock();
}
public static DistributeLock getDistributeLock(DistributeLockType type) {
switch (type) {
case REDIS:
return new RedisDistributeLock();
case ZOOKEEPER:
return new ZkDistributeLock();
default:
return new DbDistributeLock();
}
}
}
public class Log {
public static void d(String msg) {
System.out.println(System.currentTimeMillis() + " - " + Thread.currentThread().getName() + " - " + msg );
}
}
测试类
import org.junit.Test;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
public class ZkDistributeLockTest {
@Test
public void test() throws Exception {
DistributeLock distributeLock = DistributeLockFactory.getDistributeLock(DistributeLockType.ZOOKEEPER);
distributeLock.lock("testresource");
System.out.println("get locked");
Thread.sleep(10000L);
distributeLock.unLock("testresource");
}
@Test
public void testDistributeLock() {
DistributeLock distributeLock = DistributeLockFactory.getDistributeLock(DistributeLockType.ZOOKEEPER);
int threadCount = 5;
CyclicBarrier cyclicBarrier = new CyclicBarrier(threadCount);
CountDownLatch countDownLatch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
new Thread(() -> {
try {
cyclicBarrier.await();
String resource = "testcode22";
Log.d("to get lock: " + resource);
boolean locked = distributeLock.lock(resource);
if (locked) {
Log.d("has get lock: " + resource);
Thread.sleep(1000);
distributeLock.unLock(resource);
Log.d("release lock: " + resource);
} else {
Log.d("not get lock: " + resource);
}
countDownLatch.countDown();
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}