只做记录,直接上代码

父类:

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实现的更多相关文章

  1. 分布式锁2 Java非常用技术方案探讨之ZooKeeper

    前言:       由于在平时的工作中,线上服务器是分布式多台部署的,经常会面临解决分布式场景下数据一致性的问题,那么就要利用分布式锁来解决这些问题.以自己结合实际工作中的一些经验和网上看到的一些资料 ...

  2. 分布式锁2 Java非常用技术方案探讨之ZooKeeper 【转载】

    前言:       由于在平时的工作中,线上服务器是分布式多台部署的,经常会面临解决分布式场景下数据一致性的问题,那么就要利用分布式锁来解决这些问题.以自己结合实际工作中的一些经验和网上看到的一些资料 ...

  3. 分布式锁没那么难,手把手教你实现 Redis 分布锁!|保姆级教程

    书接上文 上篇文章「MySQL 可重复读,差点就让我背上了一个 P0 事故!」发布之后,收到很多小伙伴们的留言,从中又学习到很多,总结一下. 上篇文章可能举得例子有点不恰当,导致有些小伙伴没看懂为什么 ...

  4. Redis学习笔记~分布锁的使用

    回到目录 分布锁主要用在多进程共同访问同一个资源时候,用来保持同一时间段只能有一个进程执行,同时避免了并发冲突的出现,这在很多场景都会用到,像秒杀库存,抽奖库存,多操作者处理一家公司等. void T ...

  5. .net下 本地锁、redis分布式锁、zk分布式锁的实现

    为什么要用锁? 大型站点在高并发的情况下,为了保持数据最终一致性就需要用到技术方案来支持.比如:分布式锁.分布式事务.有时候我们在为了保证某一个方法每次只能被一个调用者使用的时候,这时候我们也可以锁来 ...

  6. Atitit。Cas机制 软件开发 编程语言 无锁机制 java c# php

    Atitit.Cas机制 软件开发 编程语言 无锁机制 java c# php 1. 为什么需要无锁操作1 2. 硬件支持 cas  atomic2 3. 无锁编程(Lock-Free)就是在某些应用 ...

  7. 锁(java, DB)

    知识点 事务 锁(java, DB) 多线程知识点整理 锁(java, DB) 什么是锁 对资源的访问权限进行控制 如果把一个资源(对象)比喻成屋子.就好像你进入了屋子锁上了门.你家人和贼都进不去了. ...

  8. 本地锁、redis分布式锁、zk分布式锁

    本地锁.redis分布式锁.zk分布式锁 https://www.cnblogs.com/yjq-code/p/dotnetlock.html 为什么要用锁? 大型站点在高并发的情况下,为了保持数据最 ...

  9. 通俗易懂 悲观锁、乐观锁、可重入锁、自旋锁、偏向锁、轻量/重量级锁、读写锁、各种锁及其Java实现!

    网上关于Java中锁的话题可以说资料相当丰富,但相关内容总感觉是一大串术语的罗列,让人云里雾里,读完就忘.本文希望能为Java新人做一篇通俗易懂的整合,旨在消除对各种各样锁的术语的恐惧感,对每种锁的底 ...

随机推荐

  1. Java设计模式(23)——行为模式之访问者模式(Visitor)

    一.概述 概念 作用于某个对象群中各个对象的操作.它可以使你在不改变这些对象本身的情况下,定义作用于这些对象的新操作. 引入 试想这样一个场景,在一个Collection中放入了一大堆的各种对象的引用 ...

  2. 北京Uber优步司机奖励政策(2月7日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  3. (AOSP)repo checkout指定版本

    aosp 怎么切换分支? To properly switch Android version, all you need to change is branch for your manifest ...

  4. Linux 下获取本机IP

    http://blog.csdn.net/K346K346/article/details/48231933 int main () { /* struct ifaddrs *ifap, *ifa; ...

  5. 测试FlowTable

    1.确定openvswitch模块加载#lsmod |grep oepnvswitch#/sbin/modprobe openvswitch 2.启动配置:1)默认配置rm -f /usr/local ...

  6. Awesome Flask

    Awesome Flask  A curated list of awesome Flask resources and plugins Awesome Flask Framework Admin i ...

  7. java中的比较:instanceof、equals(hashcode)、==

    import javassist.expr.Instanceof; class Person{ String s; Person(String s){ this.s=s; } } class Man ...

  8. hdu1203I NEED A OFFER!(01背包)

    I NEED A OFFER! Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)T ...

  9. php常用几个数组的区别

    本文主要介绍的php数组函数主要有:sort.rsort.asort.arsort.ksort.krsort 测试数据定义一个关联数组如下: $data=[ 'f'=>123, 'b'=> ...

  10. Linux命令应用大词典-第2章 获取帮助

    2.1 help:查看内部Shell命令帮助信息 2.2 man:显示在线手册页 2.3 manpath:查看和设置man手册页的查询路径 2.4 info:阅读info格式的文件 2.5 pinfo ...