只做记录,直接上代码

父类:

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. Jenkins中Publish Over SSH插件使用

    Publish Over SSH插件安装 进入插件管理安装插件,我这里已经安装过了所以在installed里面,没安装过去available里面搜索. 系统设置中配置Publish Over SSH ...

  2. go内建容器-Map

    1.基础定义 golang中的map如同它的函数一样"纯粹",map就是用来存储键值对的容器,别管什么哈希不哈希的(底层已实现),用就行 //创建一个map m := map[st ...

  3. 佛山Uber优步司机奖励政策(12月28日到1月3日)

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

  4. Java语言简介

    Java即计算机编程语言 1.概念 Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承.指针等概念,因此Java语言具有功能强大和简单易用两个特征.Jav ...

  5. Ubentu下命令行安装chrome浏览器

    前言: 最近在使用Ubuntu 系统.编译Android aosp 项目.准备写博客,但是Ubuntu 的默认浏览器 firefox 在写csdn 的时候,加载不出来.如下图 一直卡在这里. 这种情况 ...

  6. K8S全栈容器服务如何助力企业云化创新?

    容器编排管理平台Kubernetes在实践两年多后,市场主导地位被正式确定,随着首批认证服务商的宣布,围绕着容器的应用编排部署服务已然成熟,Kubernetes开始在商业场景为企业创造价值.华为云在K ...

  7. 使用 Fiddler工具模拟post四种请求数据

    post请求主体详解: 对于get请求来说没有请求主体entity-body.对于post请求而言,不会对发送请求的数据格式进行限制,理论上你可以发任意数据,但是服务器能不能处理就是另一回事了.服务器 ...

  8. 前端开发工程师 - 05.产品前端架构 - 协作流程 & 接口设计 & 版本管理 & 技术选型 &开发实践

    05.产品前端架构 第1章--协作流程 WEB系统 角色定义 协作流程 职责说明 第2章--接口设计 概述 接口规范 规范应用 本地开发 第3章--版本管理 见 Java开发工程师(Web方向) - ...

  9. 【movable-area、movable-view】 可移动区域组件说明

    movable-area.movable-view 可移动区域组件 原型: <movable-area scale-area="[Boolean]"> <mova ...

  10. lintcode735. Replace With Greatest From Right

    Given an array of integers, replace every element with the next greatest element (greatest element o ...