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新人做一篇通俗易懂的整合,旨在消除对各种各样锁的术语的恐惧感,对每种锁的底 ...
随机推荐
- go学习笔记-反射(Reflection)
反射(Reflection) 反射是利用reflect包实现的 反射可大大提高程序的灵活性,使得interface{}有更大的发挥余地 反射使用TypeOf和ValueOf函数从接口中获取目标对象信息 ...
- 【8086汇编-Day5】第三次实验
练习一 结果展示: 这个程序执行下来貌似打印了数字36,但其实是两个数字3.6: 这段就是用来打印3:首先ah里放2,跟后面的int 21h结合起来就是调用21号中断例程的2号子程序,用来打印到标准输 ...
- Python概述
1.什么是Python? Python是一种解释型,面向对象,动态数据类型的高级程序设计语言. Python由Guido van Rossum于1989年底发明,第一个公开发行版发行于1991年. 像 ...
- 海思NB-IOT死机问题解决记录
1. 首先抓下LOG的信息,这个应该是MCU到NB的数据 2. 看下NB到MCU的数据 3. 总结起来,只看到了NB模块的启动,似乎AT指令,肯本没收到.测试中确实出现了复位,但是不清楚是发送的AT指 ...
- C#中Mutex的用法
C#中Mutex是互斥锁,位于System.Threading 命名空间中. 顾名思义,它是一个互斥的对象,同一时间只有一个线程可以拥有它,该类还可用于进程间同步的同步基元. 如果当前有一个线程拥有它 ...
- 第四模块:网络编程进阶&数据库开发 第1章·网络编程进阶
01-进程与程序的概念 02-操作系统介绍 03-操作系统发展历史-第一代计算机 04-操作系统发展历史-批处理系统 05-操作系统发展历史-多道技术 06-操作系统发展历史-分时操作系统 07-总结 ...
- Python递归算法入门
递归是一种算法,它在编程里面有着广泛的应用: 1. 递归必须满足哪两个基本条件? 一.函数调用自身 二.设置了正确的返回条件 2. 思考一下,按照递归的特性,在编程中有没有不得不使用递归的情况? 答: ...
- 一步一步图文介绍SpriteKit使用TexturePacker导出的纹理集Altas
1.为什么要使用纹理集? 游戏是一种很耗费资源的应用,特别是在移动设备中的游戏,性能优化是非常重要的 纹理集是将多张小图合成一张大图,使用纹理集有以下优点: 1.减少内存占用,减少磁盘占用: 2.减少 ...
- [CF19B]Checkout Assistant
题目描述 Bob 来到一家现购自运商店,将 n 件商品放入了他的手推车,然后到收银台 付款.每件商品由它的价格 pi 和收银员扫描它的时间 ti 秒定义.当收银员正在扫 描某件商品时,Bob 可以从他 ...
- C 判断成绩是否及格
#include <stdio.h> int main(int argc, char **argv) { // 新建两个变量 pass代表及格分数的固定变量 score代表学生成绩的一个 ...