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新人做一篇通俗易懂的整合,旨在消除对各种各样锁的术语的恐惧感,对每种锁的底 ...
随机推荐
- Git安装配置(Linux)
使用yum安装Git yum install git -y 编译安装 # 安装依赖关系 yum install curl-devel expat-devel gettext-devel openssl ...
- vimrc 配置
" All system-wide defaults are set in $VIMRUNTIME/debian.vim and sourced by" the call to : ...
- Java设计模式(12)——结构型模式之门面模式(Facade)
一.概述 概念 简要示意图(没有一个统一的UML图) 角色 门面角色:门面模式核心,它被客户端调用,并且熟悉子系统 子系统角色:子系统,子系统并不知道门面的存在,门面对它来说只不过是另外一个客户端 ...
- APP如何发布到Google play 商店
APP如何发布到Google play 商店?以及有哪些需要注意的点 2015-05-13 10:07 19773人阅读 评论(1) 收藏 举报 分类: iPhone游戏开发(330) 链接:ht ...
- 下载地图瓦片(包括各种格式的,Openstreetmap,googlemap, bingmap)
参考第三方开源库Brutile 个人的程序托管在github上
- androd hook acitivity 启动流程,替换启动的activity(Android Instrumentation)
前言:如果程序想要知道有activity启动,如果想要拦截activity,然后跳转到指定的activity怎么办? 我们看下ActivityThread 里面: private Activity p ...
- spring源码-BeanFactoryPostProcessor-3.2
一.BeanFactoryPostProcessor这个是spring容器的拓展之一,其目的是在容器初始化完成之前,通过beanFactory对上下文进行进行操作. 二.常用场景,需要对beanDef ...
- MongoDB之我是怎么成为Primary节点的
此文已由作者温正湖授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. Primary(主)是MongoDB复制集中的最重要的角色,是能够接受客户端/Driver写请求的节点,(读 ...
- Ruby 基础教程1-7
函数: foo(x,y,z) foo(x,*args) foo(x,*args,c) foo(x=0,y="a") 2.0以后参数可以关键字指定 foo(x:0,y:0,z:0) ...
- hdu5305 Friends(dfs,多校题)
Friends Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Sub ...