启动zookeeper
pom.xml
org.apache.curator
curator-recipes
2.9.1
配置zookeeper
package com.example.demo;
/**
* @program: zookeeperlock
* @description
* @author: dajitui
* @create: 2019-01-05 23:50
**/
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.RetryNTimes;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CuratorConfiguration {
@Value("${curator.retryCount}")
private int retryCount;
@Value("${curator.elapsedTimeMs}")
private int elapsedTimeMs;
@Value("${curator.connectString}")
private String connectString;
@Value("${curator.sessionTimeoutMs}")
private int sessionTimeoutMs;
@Value("${curator.connectionTimeoutMs}")
private int connectionTimeoutMs;
@Bean(initMethod = "start")
public CuratorFramework curatorFramework() {
return CuratorFrameworkFactory.newClient(
connectString,
sessionTimeoutMs,
connectionTimeoutMs,
new RetryNTimes(retryCount, elapsedTimeMs));
}
}
封装zookeeper工具类
package com.example.demo.util;
/**
* @program: zookeeperlock
* @description
* @author: dajitui
* @create: 2019-01-05 23:51
**/
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooDefs;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.concurrent.CountDownLatch;
@Service
public class DistributedLockByCurator implements InitializingBean{
private static final Logger logger = LoggerFactory.getLogger(DistributedLockByCurator.class);
private final static String ROOT_PATH_LOCK = "rootlock";
private CountDownLatch countDownLatch = new CountDownLatch(1);
@Autowired
private CuratorFramework curatorFramework;
/**
* 获取分布式锁
*/
public void acquireDistributedLock(String path) {
String keyPath = "/" + ROOT_PATH_LOCK + "/" + path;
while (true) {
try {
curatorFramework
.create()
.creatingParentsIfNeeded()
.withMode(CreateMode.EPHEMERAL)
.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
.forPath(keyPath);
logger.info("success to acquire lock for path:{}", keyPath);
break;
} catch (Exception e) {
logger.info("failed to acquire lock for path:{}", keyPath);
logger.info("while try again .......");
try {
if (countDownLatch.getCount() <= 0) {
countDownLatch = new CountDownLatch(1);
}
countDownLatch.await();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
}
/**
* 释放分布式锁
*/
public boolean releaseDistributedLock(String path) {
try {
String keyPath = "/" + ROOT_PATH_LOCK + "/" + path;
if (curatorFramework.checkExists().forPath(keyPath) != null) {
curatorFramework.delete().forPath(keyPath);
}
} catch (Exception e) {
logger.error("failed to release lock");
return false;
}
return true;
}
/**
* 创建 watcher 事件
*/
private void addWatcher(String path) throws Exception {
String keyPath;
if (path.equals(ROOT_PATH_LOCK)) {
keyPath = "/" + path;
} else {
keyPath = "/" + ROOT_PATH_LOCK + "/" + path;
}
final PathChildrenCache cache = new PathChildrenCache(curatorFramework, keyPath, false);
cache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);
cache.getListenable().addListener((client, event) -> {
if (event.getType().equals(PathChildrenCacheEvent.Type.CHILD_REMOVED)) {
String oldPath = event.getData().getPath();
logger.info("success to release lock for path:{}", oldPath);
if (oldPath.contains(path)) {
//释放计数器,让当前的请求获取锁
countDownLatch.countDown();
}
}
});
}
//创建父节点,并创建永久节点
@Override
public void afterPropertiesSet() {
curatorFramework = curatorFramework.usingNamespace("lock-namespace");
String path = "/" + ROOT_PATH_LOCK;
try {
if (curatorFramework.checkExists().forPath(path) == null) {
curatorFramework.create()
.creatingParentsIfNeeded()
.withMode(CreateMode.PERSISTENT)
.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
.forPath(path);
}
addWatcher(ROOT_PATH_LOCK);
logger.info("root path 的 watcher 事件创建成功");
} catch (Exception e) {
logger.error("connect zookeeper fail,please check the log >> {}", e.getMessage(), e);
}
}
}
测试类
package com.example.demo.controller;
import com.example.demo.util.DistributedLockByCurator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @program: zookeeperlock
* @description
* @author: dajitui
* @create: 2019-01-06 00:19
**/
@RestController
public class testController {
@Autowired
private DistributedLockByCurator distributedLockByCurator;
private static String path = "dajitui";
@RequestMapping(value = "/curator/lock1")
public void a() {
distributedLockByCurator.acquireDistributedLock(path);
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
distributedLockByCurator.releaseDistributedLock(path);
}
@RequestMapping(value = "/curator/lock2")
public void b() {
distributedLockByCurator.acquireDistributedLock(path);
try {
Thread.sleep(15000);
} catch (InterruptedException e) {
e.printStackTrace();
}
distributedLockByCurator.releaseDistributedLock(path);
}
}
浏览器分别访问/curator/lock1,还有/curator/lock2
控制台会出现:
/curator/lock1休眠20秒,/curator/lock2会休眠15秒,中间出现获取分布锁失败
至于原理看这里https://blog.csdn.net/qiangcuo6087/article/details/79067136
客户端连接Zookeeper的时候都会产生节点,判断节点是否存在来锁住程序