package com.atguigu.Lock;
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;
public class DistributeLock {
private final String connectString = "192.168.0.112:2181";
private final int sessionTimeOut = 100000;
private final ZooKeeper zkServer;
private CountDownLatch connectLatch = new CountDownLatch(1);
private CountDownLatch waitLatch = new CountDownLatch(1);
//前一个节点的名称
private String waitPath;
private String currentMode;
public DistributeLock() throws IOException, InterruptedException, KeeperException {
//获取连接
zkServer = new ZooKeeper(connectString, sessionTimeOut, new Watcher() {
public void process(WatchedEvent watchedEvent) {
//connectLatch 如果连接上ZK。可以释放
if (watchedEvent.getState() == Event.KeeperState.SyncConnected) {
connectLatch.countDown();
}
//waitLatch 需要释放
if (watchedEvent.getType() == Event.EventType.NodeDeleted && watchedEvent.getPath().equals(waitPath)) {
waitLatch.countDown();
}
}
});
//等待zookeeper正常连接后,往下走。
connectLatch.await();
//判断根节点/lock是否存在
Stat stat = zkServer.exists("/locks", false);
if (stat == null) {
//不存在,创建根节点
zkServer.create("/locks", "locks".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
}
//加锁
public void zkLock() {
//创建对应的临时顺序节点
try {
currentMode = zkServer.create("/locks/" + "seq-", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
//判断对应的临时顺序节点是否是最小的序号节点,如果是获取到锁,如果不是,监听他序号前一个节点
List<String> children = zkServer.getChildren("/locks", false);
//如果children中只有一个值,那就直接获取锁
if (children.size() == 1) {
return;
} else {
//如果有多个节点,需要判断谁最小
Collections.sort(children);
//获取节点名称 (seq-000000)
String thisnode = currentMode.substring("/locks/".length());
//通过seq-00000获取该节点在children集合中的位置
int index = children.indexOf(thisnode);
//判断
if (index == -1) {
System.out.println("数据异常");
} else if (index == 0) {
//就一个节点,获取锁
return;
} else {
//需要进行监听他前面的节点
waitPath = "/locks/" + children.get(index - 1);
zkServer.getData(waitPath, true, null);
waitLatch.await();
return;
}
}
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//解锁
public void unZkLock() throws KeeperException, InterruptedException {
//删除节点
zkServer.delete(currentMode,-1);
}
}
package com.atguigu.zk;
import com.atguigu.Lock.DistributeLock;
import org.apache.zookeeper.KeeperException;
import java.io.IOException;
//Zookeeper 分布式锁的测试
public class LockTest {
public static void main(String[] args) throws InterruptedException, IOException, KeeperException {
final DistributeLock Lock1 = new DistributeLock();
final DistributeLock Lock2 = new DistributeLock();
new Thread(new Runnable() {
public void run() {
try {
Lock1.zkLock();
System.out.println("线程1 启动,获取到锁");
Thread.sleep(5 * 1000);
Lock1.unZkLock();
System.out.println("线程1 启动,释放锁");
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
public void run() {
try {
Lock2.zkLock();
System.out.println("线程2 启动,获取到锁");
Thread.sleep(5 * 1000);
Lock2.unZkLock();
System.out.println("线程2 启动,释放锁");
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
结果
输出