分布式锁-基于Zookeeper实现
文章目录
1. Zookeeper安装部署
1.1 安装部署参考文档
分布式注册中心-Zookeeper: https://blog.youkuaiyun.com/qq_41112063/article/details/105312845
1.2 Zookeeper客户端工具
下载地址:https://issues.apache.org/jira/secure/attachment/12436620/ZooInspector.zip
2. 实现原理
- 多个JVM同时在根节点下创建临时节点(/lock)
- 创建临时节点(/lock)成功,则获取锁成功,执行响应的逻辑代码
- 创建临时节点(/lock)失败,则获取锁失败,通过订阅节点删除通知事件,如果节点删除则重新获取锁,否则就一直等待
- 执行响应业务逻辑完成后关闭连接,临时节点删除,锁释放
3. 具体实现
3.1 引入Gradle依赖
dependencies {
compile group: 'com.101tec', name: 'zkclient', version: '0.11'
}
3.2 具体业务实现
3.2.1 创建CustomLock接口
public interface CustomLock {
/**
* 获取锁
*/
public void getLock();
/**
* 释放锁
*/
public void unLock();
}
3.2.2 创建ZookeeperAbstractLock抽象类
public abstract class ZookeeperAbstractLock implements CustomLock {
// zk连接地址
private String CONNECTSTRING = "114.55.34.44:2181";
// 创建zk连接
protected ZkClient zkClient = new ZkClient(CONNECTSTRING);
// zk节点创建路径目录
protected String PATH = "/lock";
// 通过定义计数器标识创建临时节点状态
protected CountDownLatch countDownLatch = new CountDownLatch(1);
/**
* 获取锁
*/
@Override
public void getLock() {
if (tryLock()) {
System.out.println("获取lock锁的资源");
} else {
// 等待
waitLock();
// 重新获取锁资源
getLock();
}
}
/**
* 释放锁
*/
@Override
public void unLock() {
if (zkClient != null) {
zkClient.close();
System.out.println("释放lock锁资源");
}
}
protected abstract void waitLock();
protected abstract boolean tryLock();
}
3.2.3 创建ZookeeperDistrbuteLock抽象类
public class ZookeeperDistrbuteLock extends ZookeeperAbstractLock {
@Override
protected void waitLock() {
IZkDataListener iZkDataListener = new IZkDataListener() {
/**
* 节点发生改变时事件通知
* @param dataPath
* @param data
* @throws Exception
*/
@Override
public void handleDataChange(String dataPath, Object data) throws Exception {
}
/**
* 节点删除是事件通知
* @param dataPath
* @throws Exception
*/
@Override
public void handleDataDeleted(String dataPath) throws Exception {
System.out.println("删除的节点路径为" + dataPath);
// 唤醒等待的线程
if (countDownLatch != null) {
countDownLatch.countDown();
}
}
};
//注册监听事件
zkClient.subscribeDataChanges(PATH, iZkDataListener);
if (zkClient.exists(PATH)) {
countDownLatch = new CountDownLatch(1);
try {
countDownLatch.await();
} catch (Exception e) {
e.printStackTrace();
}
}
//删除监听事件
zkClient.unsubscribeDataChanges(PATH, iZkDataListener);
}
@Override
protected boolean tryLock() {
try {
zkClient.createEphemeral(PATH);
System.out.println("获取lock锁成功");
return true;
} catch (Exception e) {
System.out.println("获取lock锁失败");
return false;
}
}
}
3.2.4 使用Zookeeper实现分布式锁
public class NumberGenerator {
// 生成订单号规则
private static int count = 0;
public String getNumber() {
// try {
// Thread.sleep(200);
// } catch (Exception e) {
// e.printStackTrace();
// }
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
return simpleDateFormat.format(new Date()) + "-" + ++count;
}
}
public class OrderService implements Runnable {
private NumberGenerator numberGenerator = new NumberGenerator();
private CustomLock customLock = new ZookeeperDistrbuteLock();
@Override
public void run() {
getNumber();
}
public void getNumber() {
try {
customLock.getLock();
String number = numberGenerator.getNumber();
System.out.println(Thread.currentThread().getName() + "生成订单号:" + number);
} catch (Exception e) {
e.printStackTrace();
} finally {
customLock.unLock();
}
}
}
public class LockTest {
/**
* 根据cpu的数量动态的配置核心线程数和最大线程数
*/
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
/**
* 核心线程数 = CPU核心数 + 1
*/
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
/**
* 线程池最大线程数 = CPU核心数 * 2 + 1
*/
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
/**
* 非核心线程闲置时超时1s
*/
private static final int KEEP_ALIVE = 1;
public static void main(String[] args) {
System.out.println("开始生成订单号......");
long begin = System.currentTimeMillis();
for (int i = 0; i < 10; i++) {
new Thread(new OrderService()).start();
}
long end = System.currentTimeMillis();
long result = end - begin;
System.out.println("执行消耗时长:" + result / 1000 + "s");
}
}