package zk;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
public class ZKLock {
//使用静态变量保证一个JVM里面只有一个ZKLock下只有一个ZooKeeper
private static ZooKeeper zooKeeper;
//zk节点
private String path;
//静太重入锁
private static ReentrantLock reentrantLock=new ReentrantLock();
public ZKLock(String host,String path){
this.path=path;
//多实例环境下保存只初始化一次
if(zooKeeper==null){
reentrantLock.lock();
if(zooKeeper==null) initZK(host);
reentrantLock.unlock();
}
}
public void lock() {
//先保证单个JVM锁
reentrantLock.lock();
//再保证分布式锁
distributeLock();
reentrantLock.unlock();
}
private void distributeLock(){
//保存一个当前线程信息
Thread t=Thread.currentThread();
//再保证分布式锁
while (true){
Stat stat=null;
try {
stat = zooKeeper.exists(path, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
//此方法为另一个线程调用
if(watchedEvent.getType()== Event.EventType.NodeDeleted){
//用当前线程unpark
LockSupport.unpark(t);
}
}
});
}catch (Exception ex){
ex.printStackTrace();
}
//是否成功获取到了锁
boolean lk=false;
if(stat==null){
//创建锁节点
try {
//因为判断是否存在一个节点和创建一个节点并不是原子操作,
// 所以这里有可能会创建失败,所以需要注意NodeExistsException异常情况
zooKeeper.create(path, "0000".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
lk=true;
}catch (KeeperException.NodeExistsException ex){
//让出CPU调度,进入下一次尝试获取锁
Thread.yield();
continue;
}catch (Exception ex){
}
if(lk){
break;
}
}else{
LockSupport.park();
}
}
}
public void release(){
//删除NODE
try {
zooKeeper.delete(path,-1);
}catch (Exception ex){}
}
//初始化zooKeeper变量
private static void initZK(String host){
try {
zooKeeper=new ZooKeeper(host, 10000000, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
}
});
}catch (Exception ex){}
}
}
测试
package zk;
public class zkTest {
static int i=0;
public static void main(String[] args) throws Exception {
String host="192.168.1.235:2181";
ZKLock lock=new ZKLock(host,"/lock");
ZKLock lock2=new ZKLock(host,"/lock");
for (int j = 0; j < 1000; j++) {
int finalJ = j;
new Thread(()->{
lock.lock();
i++;
lock.release();
}).start();
}
for (int j = 0; j < 1000; j++) {
int finalJ = j;
new Thread(()->{
lock2.lock();
i++;
lock2.release();
}).start();
}
while (Thread.activeCount()>3){
//System.out.println(Thread.activeCount());
Thread.yield();
}
System.out.println("最终结果:"+i);
}
}