zk分布锁的java实现
只做记录,直接上代码
父类:
package com.ylcloud.common.lock; import com.alibaba.fastjson.JSON;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.serialize.SerializableSerializer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; /**
* @author cjh
* @Description: zk分布锁
* @date: 2018/9/27 11:36
*/
public class ZkLock { private static Logger logger = LogManager.getLogger(ZkLock.class); public static String ZOOKEEPER_IP_PORT = "127.0.0.1:2181"; public static Integer sessionTimeout = 30000; public static Integer connectTimeout = 30000; /**
* 节点锁标记
*/
public String lockPath; /**
* 前一个节点(设置用户添加监听器)
*/
public String beforeNode; /**
* 当前执行节点(设置用于删除)
*/
public String currentNode; /**
* 当前请求节点
*/
public String threadTag = null; private String lock1 = null; private String lock2 = null; public static final ZkClient client = new ZkClient(ZOOKEEPER_IP_PORT, sessionTimeout, connectTimeout, new SerializableSerializer()); private static final ThreadLocal<String> NODES = new ThreadLocal<String>(); public ZkLock() {
} public void init(String code) {
this.lockPath = code;
this.lock1 = code + "LOCK";
this.lock2 = code + "UNLOCK";
client.deleteRecursive(lockPath);
} public void lock() { synchronized (lock1) {
if (!client.exists(lockPath)) {
client.createPersistent(lockPath);
} if (!tryLock()) {
} } } public void unlock() { List<String> childrens = client.getChildren(lockPath);
Collections.sort(childrens); String nodes = NODES.get();
logger.info(JSON.toJSONString(childrens) + " ==== " + nodes + " ==== " + (nodes.equals(lockPath + '/' + childrens.get(0))));
if (childrens.size() > 0 && nodes.equals(lockPath + '/' + childrens.get(0))) {
client.delete(nodes);
} } private boolean tryLock() { threadTag = client.createEphemeralSequential(lockPath + '/', ""); NODES.set(threadTag); List<String> childrens = client.getChildren(lockPath);
Collections.sort(childrens); currentNode = lockPath + '/' + childrens.get(0); if (threadTag.equals(currentNode)) {
return true;
} else { currentNode = threadTag; int wz = Collections.binarySearch(childrens, threadTag.substring(lockPath.length() + 1));
beforeNode = lockPath + '/' + childrens.get(wz - 1); final CountDownLatch latch = new CountDownLatch(1);
try { client.subscribeDataChanges(beforeNode, new IZkDataListener() { @Override
public void handleDataDeleted(String dataPath) throws Exception {
if (latch != null && latch.getCount() > 0) {
latch.countDown();
}
} @Override
public void handleDataChange(String dataPath, Object data) throws Exception {
}
}); if (client.exists(beforeNode)) {
latch.await(sessionTimeout, TimeUnit.MILLISECONDS);
} } catch (Exception e) {
return true;
} finally {
} }
return false;
} }
子类
package com.ylcloud.common.lock.ext; import com.ylcloud.common.lock.ZkLock; /**
* @Description: 用户编码锁
* @author cjh
* @date: 2018/10/10 14:47
*/
public class ZkLockUserCode extends ZkLock { public ZkLockUserCode() {
super.init("/USER_CODE");
} }
使用示例:
private ZkLock zkLock = new ZkLockUserCode();
public void addUser() {
try {
zkLock.lock();
/**
*业务实现
*/
} catch (Exception e) {
logger.info("err {} {} ", e.getMessage(), e.getCause());
} finally {
zkLock.unlock();
}
}
注意:unlock必须写在finally里面,否则一旦业务出现运行错误造成没有解锁,下一次访问的人就需要等待一个sessionTime了
题外话:zk在linux上启动命令 ./zkServer.sh start
自己实现的很多细节没考虑到导致在高并发的项目中出现了问题,然后我改用了Curator框架来操控zookeeper实现分布锁:
<curator.version>4.0.0</curator.version>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>${curator.version}</version>
</dependency>
锁实现代码:
package com.ylcloud.common.lock; import com.ylcloud.common.lock.ext.ZkLockRoleCode;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.serialize.SerializableSerializer;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; /**
* @author cjh
* @Description: zk分布锁
* @date: 2018/9/27 11:36
*/
public class ZkLock { private static Logger logger = LogManager.getLogger(ZkLock.class); public static String ZOOKEEPER_IP_PORT = "127.0.0.1:2181"; public static String NAME_SPACE = "YL_CLOUD"; public static Integer sessionTimeout = 15000; public static Integer connectTimeout = 30000; private static Object initLock = new Object(); public static CuratorFramework client = null; private static Map<String,ZkLock> tagLocks = new HashMap<String,ZkLock>(); public ZkLock() {
} public InterProcessMutex mutex = null; static {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
client =
CuratorFrameworkFactory.builder()
.connectString(ZOOKEEPER_IP_PORT)
.sessionTimeoutMs(sessionTimeout)
.connectionTimeoutMs(connectTimeout)
.retryPolicy(retryPolicy)
.namespace(NAME_SPACE)
.build(); client.start();
} public void init(String code) {
this.mutex = new InterProcessMutex(client,code);
} //prefix 标记 code 主键
public static ZkLock getTagLock(String prefix,String code){
String tag = prefix + "/" + code; if(!tagLocks.containsKey(tag)){
synchronized (initLock){
if(!tagLocks.containsKey(tag)){
ZkLock zkLock = new ZkLock();
zkLock.init(tag);
tagLocks.put(tag,zkLock);
}
}
} return tagLocks.get(tag);
} public void lock(){
try {
this.mutex.acquire();
} catch (Exception e) {
logger.error("加锁失败");
}
} public void unlock(){
try {
this.mutex.release();
} catch (Exception e) {
logger.error("锁释放失败");
}
} }
调用代码(不变)
转载请注明博客出处:http://www.cnblogs.com/cjh-notes/
zk分布锁的java实现的更多相关文章
- 分布式锁2 Java非常用技术方案探讨之ZooKeeper
前言: 由于在平时的工作中,线上服务器是分布式多台部署的,经常会面临解决分布式场景下数据一致性的问题,那么就要利用分布式锁来解决这些问题.以自己结合实际工作中的一些经验和网上看到的一些资料 ...
- 分布式锁2 Java非常用技术方案探讨之ZooKeeper 【转载】
前言: 由于在平时的工作中,线上服务器是分布式多台部署的,经常会面临解决分布式场景下数据一致性的问题,那么就要利用分布式锁来解决这些问题.以自己结合实际工作中的一些经验和网上看到的一些资料 ...
- 分布式锁没那么难,手把手教你实现 Redis 分布锁!|保姆级教程
书接上文 上篇文章「MySQL 可重复读,差点就让我背上了一个 P0 事故!」发布之后,收到很多小伙伴们的留言,从中又学习到很多,总结一下. 上篇文章可能举得例子有点不恰当,导致有些小伙伴没看懂为什么 ...
- Redis学习笔记~分布锁的使用
回到目录 分布锁主要用在多进程共同访问同一个资源时候,用来保持同一时间段只能有一个进程执行,同时避免了并发冲突的出现,这在很多场景都会用到,像秒杀库存,抽奖库存,多操作者处理一家公司等. void T ...
- .net下 本地锁、redis分布式锁、zk分布式锁的实现
为什么要用锁? 大型站点在高并发的情况下,为了保持数据最终一致性就需要用到技术方案来支持.比如:分布式锁.分布式事务.有时候我们在为了保证某一个方法每次只能被一个调用者使用的时候,这时候我们也可以锁来 ...
- Atitit。Cas机制 软件开发 编程语言 无锁机制 java c# php
Atitit.Cas机制 软件开发 编程语言 无锁机制 java c# php 1. 为什么需要无锁操作1 2. 硬件支持 cas atomic2 3. 无锁编程(Lock-Free)就是在某些应用 ...
- 锁(java, DB)
知识点 事务 锁(java, DB) 多线程知识点整理 锁(java, DB) 什么是锁 对资源的访问权限进行控制 如果把一个资源(对象)比喻成屋子.就好像你进入了屋子锁上了门.你家人和贼都进不去了. ...
- 本地锁、redis分布式锁、zk分布式锁
本地锁.redis分布式锁.zk分布式锁 https://www.cnblogs.com/yjq-code/p/dotnetlock.html 为什么要用锁? 大型站点在高并发的情况下,为了保持数据最 ...
- 通俗易懂 悲观锁、乐观锁、可重入锁、自旋锁、偏向锁、轻量/重量级锁、读写锁、各种锁及其Java实现!
网上关于Java中锁的话题可以说资料相当丰富,但相关内容总感觉是一大串术语的罗列,让人云里雾里,读完就忘.本文希望能为Java新人做一篇通俗易懂的整合,旨在消除对各种各样锁的术语的恐惧感,对每种锁的底 ...
随机推荐
- CSS布局遇到的问题小结
clear属性的作用 指定某个元素的一侧不能出现浮动元素.它是通过为这个元素在上边距之外增加空间,从而使得这个元素的顶部和浮动元素的底部对齐.这里作用的仅仅是同一个bfc下的浮动元素. This pr ...
- jmeter开发自己的sampler插件
1. 新建maven工程 2.pom文件引入jmeter的核心包 <project xmlns="http://maven.apache.org/POM/4.0.0" xml ...
- vue2组件之间双向数据绑定问题
最近在使用element-ui的dialog组件二次封装成独立组件使用时,子组件需要将关闭dialog状态返回给父组件,简单的说就是要实现父子组件之间的数据双向绑定问题. 大致代码如下: 1,父组件 ...
- C语言灵魂--指针
什么是指针?理解指针之前得知道什么是地址. 1.数据在计算机中的存储形式: 数据在计算机中是以二进制的形式存储的.计算机的存储器是用半导体集成电路构成的,有N多个二极管元件组成. 每一个二极管元件就如 ...
- Qt-QML-Connections,接受组件信号
这里还没有什么新的体会.就直接上代码,在上篇一处上改出来的 import QtQuick 2.5 import QtQuick.Controls 1.4 ApplicationWindow { vis ...
- WEB安全--高级sql注入,爆错注入,布尔盲注,时间盲注
1.爆错注入 什么情况想能使用报错注入------------页面返回连接错误信息 常用函数 updatexml()if...floorextractvalue updatexml(,concat() ...
- requests,lxml爬启信宝
首先, 添加requests模块: 然后, 添加lxml模块: 启信宝登录抓包: QiXinBao.py: import requestsfrom lxml import etree loginUrl ...
- Git 与 GitHub
Git 这个年代,不会点Git真不行啦,少年别问问什么,在公司你就知道了~ Git是一个协同开发的工具,主要作用是进行版本控制,而且还能自动检测代码是否发生变化. 一. 安装 下载地址:https:/ ...
- Microbit MicroPython 介绍
Python 是全世界最受欢迎的程序语言之一(world’s most popular ) .如果不特别说明,你可能每天在使用Python 写成的软件而不知道.像许多著名的公司跟组织如 Google, ...
- Unity与服务区交互数据
Unity与服务区交互数据 Unity可能在用的时候使用到登陆等需要与服务器交互数据.今天尝试使用了WWW类和WWWForm类来实现Get请求与Post请求. 1.WWW Unity圣典解释: WWW ...