利用Zookeeper实现分布式锁
1、分布式锁是什么?
分布式锁是控制分布式系统之间同步访问共享资源的一种方式。
2、为什么需要分布式锁?
在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。
3、乐观锁和悲观锁含义
悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。
两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行retry,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。
本段参考了:http://blog.csdn.net/hongchangfirst/article/details/26004335
4、具体实现
本文采用zookeeper第三方库curator实现分布式锁。
1、添加依赖
<!-- Curator对Zookeeper封装 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.9.1</version>
</dependency> <!-- Curator对Zookeeper封装 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-client</artifactId>
<version>2.9.1</version>
</dependency> <!-- Curator对Zookeeper封装 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.9.1</version>
</dependency>
2、锁的实现
package com.mao;
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; /**
*
* 项目名称:---
* 模块名称:公共服务-锁工具
* 功能描述:锁工具类(基于Zookeeper)
* 创建人: mao2080@sina.com
* 创建时间:2017年4月20日 下午4:35:56
* 修改人: mao2080@sina.com
* 修改时间:2017年4月20日 下午4:35:56
*/
public class ZKLockUtil { /**Zookeeper注册中心地址*/
private static final String ZOOKEEPER_SERVER; /**获取锁-每次尝试间隔(单位:毫秒)*/
private static final int BASE_SLEEP_TIME = 1000; /**获取锁-最大尝试次数*/
private static final int MAX_RETRIES = 5; /**Curator锁对象*/
private InterProcessMutex lock; /**Curator客户端*/
private CuratorFramework client; /**分布式锁根节点*/
private static final String ZK_BASE_LOCK_PATH = "/Locks/"; /**
* 初始化Zookeeper注册中心地址
*/
static {
ZOOKEEPER_SERVER = "172.24.20.214";
}
/**
*
* 描述:构造函数
* @author mao2080@sina.com
* @created 2017年4月20日 下午3:52:53
* @since
* @param businessType 业务类型
* @param baseSleepTimeMs 获取锁-每次尝试间隔(单位:毫秒)
* @param maxRetries 获取锁-最大尝试次数
* @throws BusinessException
*/
private void initService(BusinessType businessType, int baseSleepTimeMs, int maxRetries) throws Exception {
if(isBlank(ZKLockUtil.ZOOKEEPER_SERVER)){
throw new Exception();
}
if(businessType == null || isBlank(businessType.getCode())){
throw new Exception();
}
try {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(baseSleepTimeMs, maxRetries);
this.client = CuratorFrameworkFactory.newClient(ZKLockUtil.ZOOKEEPER_SERVER, retryPolicy);
this.client.start();
this.setLock(new InterProcessMutex(this.client, ZK_BASE_LOCK_PATH.concat(businessType.getCode())));
} catch (Exception e) {
throw new Exception();
}
} /**
*
* 描述:构造函数
* @author mao2080@sina.com
* @created 2017年4月20日 下午3:52:44
* @since
* @param businessType 业务类型
* @throws BusinessException
*/
public ZKLockUtil(BusinessType businessType) throws Exception {
this.initService(businessType, ZKLockUtil.BASE_SLEEP_TIME, ZKLockUtil.MAX_RETRIES);
} /**
*
* 描述:构造函数
* @author mao2080@sina.com
* @created 2017年4月20日 下午3:52:53
* @since
* @param businessType 业务类型
* @param baseSleepTimeMs 获取锁-每次尝试间隔(单位:毫秒)
* @param maxRetries 获取锁-最大尝试次数
* @throws BusinessException
*/
public ZKLockUtil(BusinessType businessType, int baseSleepTimeMs, int maxRetries) throws Exception {
this.initService(businessType, baseSleepTimeMs, maxRetries);
} /**
*
* 描述:释放资源
* @author mao2080@sina.com
* @created 2017年4月20日 下午3:58:03
* @since
*/
public void close(){
try {
this.getLock().release();
} catch (Exception e) {
e.printStackTrace();
}
try {
this.client.close();
} catch (Exception e) {
e.printStackTrace();
}
} /**
*
* 描述:判断对象是否为空
* @author mao2080@sina.com
* @created 2017年3月20日 上午11:33:55
* @since
* @param obj
* @return
*/
public static boolean isBlank(Object obj){
if(obj == null || "".equals(obj.toString())){
return true;
}
return false;
} public InterProcessMutex getLock() {
return lock;
} public void setLock(InterProcessMutex lock) {
this.lock = lock;
} /**
*
* 项目名称:---
* 模块名称:公共服务-锁工具
* 功能描述:业务类型
* 创建人: mao2080@sina.com
* 创建时间:2017年4月22日 下午12:27:04
* 修改人: mao2080@sina.com
* 修改时间:2017年4月22日 下午12:27:04
*/
public enum BusinessType { Demo("0001", "Demo"), ; /**业务类型编码 */
private String code; /**业务类型名称 */
private String name; /**
*
* 描述:构建业务类型
* @author mao2080@sina.com
* @created 2017年4月10日 下午3:42:57
* @since
* @param code 业务类型编码
* @param name 业务类型名称
* @return
*/
private BusinessType(String code, String name) {
this.code = code;
this.name = name;
} public String getCode() {
return code;
} public void setCode(String code) {
this.code = code;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public static void main(String[] args) {
System.out.println(BusinessType.Demo.code);
} } }
3、使用场景
package com.mao; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import com.mao.ZKLockUtil.BusinessType; /**
*
* 项目名称:---
* 模块名称:公共服务-锁工具
* 功能描述:锁工具类
* 创建人: mao2080@sina.com
* 创建时间:2017年4月20日下午4:35:56
* 修改人: mao2080@sina.com
* 修改时间:2017年4月20日 下午4:35:56
*/
public class ZKLockUtilTest { /**
*
* 描述:具体使用样例
*
* @author mao2080@sina.com
* @created 2017年4月22日 下午12:29:38
* @since
* @param args
* @throws Exception
*/
public static void main1(String[] args) throws Exception {
ZKLockUtil lock = new ZKLockUtil(BusinessType.Demo);
try {
if (lock.getLock().acquire(40, TimeUnit.SECONDS)) {
System.out.println("get lock success...do work");
Thread.sleep(20000);
}
} catch (Exception e) {
System.out.println("get lock fail...," + e.getMessage());
e.printStackTrace();
} finally {
lock.close();
}
} /**
*
* 描述:启动线程模拟并发访问
*
* @author mao2080@sina.com
* @created 2017年4月22日 下午12:29:13
* @since
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(5);
ExecutorService exec = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) {
exec.submit(new MyLock("client" + i, latch));
}
exec.shutdown();
latch.await();
System.out.println("所有任务执行完毕");
} static class MyLock implements Runnable { private String name; private CountDownLatch latch; public MyLock(String name, CountDownLatch latch) {
this.name = name;
this.latch = latch;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public void run() {
ZKLockUtil locks = null;
try {
locks = new ZKLockUtil(BusinessType.Demo);
} catch (Exception e1) {
e1.printStackTrace();
return;
}
try {
if (locks.getLock().acquire(40, TimeUnit.SECONDS)) {
System.out.println("----------" + this.name+ "获得资源----------");
System.out.println("----------" + this.name+ "正在处理资源----------");
Thread.sleep(1 * 2000);
System.out.println("----------" + this.name+ "资源使用完毕----------");
latch.countDown();
}
} catch (Exception e) {
System.out.println("get lock fail...," + e.getMessage());
e.printStackTrace();
} finally {
locks.close();
}
}
}
}
4、运行结果
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
----------client1获得资源----------
----------client1正在处理资源----------
----------client1资源使用完毕----------
----------client4获得资源----------
----------client4正在处理资源----------
----------client4资源使用完毕----------
----------client2获得资源----------
----------client2正在处理资源----------
----------client2资源使用完毕----------
----------client0获得资源----------
----------client0正在处理资源----------
----------client0资源使用完毕----------
----------client3获得资源----------
----------client3正在处理资源----------
----------client3资源使用完毕----------
所有任务执行完毕
5、参考博客
1、http://blog.csdn.net/wuzhilon88/article/details/41121195
2、http://www.cnblogs.com/LiZhiW/p/4931577.html
6、本文demo下载
利用Zookeeper实现分布式锁的更多相关文章
- 利用Zookeeper实现分布式锁及服务注册中心
对于Zookeeper的定义以及原理,网上已经有很多的优秀文章对其进行了详细的介绍,所以本文不再进行这方面的阐述. 本文主要介绍一些基本的准备工作以及zookeeper.net的使用. 本文源代码gi ...
- ZooKeeper示例 分布式锁
[转载请注明作者和原文链接, 如有谬误, 欢迎在评论中指正. ] 场景描述 在分布式应用, 往往存在多个进程提供同一服务. 这些进程有可能在相同的机器上, 也有可能分布在不同的机器上. 如果这些进程 ...
- 基于 Zookeeper 的分布式锁实现
1. 背景 最近在学习 Zookeeper,在刚开始接触 Zookeeper 的时候,完全不知道 Zookeeper 有什么用.且很多资料都是将 Zookeeper 描述成一个“类 Unix/Linu ...
- 利用redis实现分布式锁
分布式锁一般有三种实现方式: 1. 数据库乐观锁: 2. 基于ZooKeeper的分布式锁: 3. 基于Redis的分布式锁: 这里大概说一下三种方式的优缺点,数据库乐观锁优点是实现简单,只需要for ...
- zookeeper — 实现分布式锁
一.前言 在之前的文章中介绍过分布式锁的特点和利用Redis实现简单的分布式锁.但是分布式锁的实现还有很多其他方式,但是万变不离其宗,始终遵循一个特点:同一时刻只能有一个操作获取.这篇文章主要介绍如何 ...
- ZooKeeper的分布式锁实现
分布式锁一般有三种实现方式: 1. 数据库乐观锁: 2. 基于Redis的分布式锁: 3. 基于ZooKeeper的分布式锁. 本篇博客将介绍第三种方式,基于Zookeeper实现分布式锁.虽然网上已 ...
- 分布式锁(3) ----- 基于zookeeper的分布式锁
分布式锁系列文章 分布式锁(1) ----- 介绍和基于数据库的分布式锁 分布式锁(2) ----- 基于redis的分布式锁 分布式锁(3) ----- 基于zookeeper的分布式锁 代码:ht ...
- Redis、Zookeeper实现分布式锁——原理与实践
Redis与分布式锁的问题已经是老生常谈了,本文尝试总结一些Redis.Zookeeper实现分布式锁的常用方案,并提供一些比较好的实践思路(基于Java).不足之处,欢迎探讨. Redis分布式锁 ...
- 基于Zookeeper的分布式锁(干干干货)
原文地址: https://juejin.im/post/5df883d96fb9a0163514d97f 介绍 为什么使用锁 锁的出现是为了解决资源争用问题,在单进程环境下的资源争夺可以使用 JDK ...
随机推荐
- windows下一步到位搭建pycharm的开发环境
pycharm的开发环境主要涉及到以下三个方面 pycharm的激活 这里采用破解的方式来达到永久激活的目的,因为激活码用着用着就过期的你,会发现不厌其烦的 通过测试,这个破解包适用于2017-201 ...
- 同步(Synchronous)和异步(Asynchronous)方法的区别
同步(Synchronous)和异步(Asynchronous)方法的区别 在讲之前,我们先来看<Computer Organization>中对于同步和异步的一个例子: 同步读写和异步读 ...
- weex animation模块 使用指南
本节学习目标 掌握内置组件animation的使用 我们在开发应用的时候,常常需要增加一些动画效果,来提高用户体验,经常用到的一些动画效果如下 平移 旋转 缩放 背景颜色改变 组件透明图 weex 提 ...
- a标签的download属性
a标签加上downlaod属性后,就可完成对href属性链接文件的下载,但仅仅是限于同源文件,如果是非同源,download属性会失效. 无download属性的时候,a标签的默认行为是链接跳转进行预 ...
- Java爬取并下载酷狗音乐
本文方法及代码仅供学习,仅供学习. 案例: 下载酷狗TOP500歌曲,代码用到的代码库包含:Jsoup.HttpClient.fastJson等. 正文: 1.分析是否可以获取到TOP500歌单 打开 ...
- DedeAMPZ 网吧能安装却不能打开网站
只需把 监听IP的连接里的 LMHOSTS查询 禁用就行了. 方法: 连接属性-->TCP/IP 协议属性-->WINS 选项卡-->去掉 启用 LMHOSTS查询 前面的勾. by ...
- shell脚本中的日期处理
Ps:这篇文章只是为了做个分类,以后有看到比较好的时间处理命令都会列在这里,您如果有什么好的时间处理命令,可以评论中添加,我会定期查看更新,谢谢! 1.定义一个参数DATE_TODAY,用于记录当天时 ...
- Windows下nginx的启动,重启,关闭功能
@echo off rem 提供Windows下nginx的启动,重启,关闭功能 echo ==================begin======================== cls :: ...
- 对于国嵌上学期《一跃进入C大门》Mini2440的代码修正
摸索了几天,加了无数的群,病急乱投医式地问了好多个人,终于改对了代码. 下面先贴出给的范例代码 这是C语言代码,是没有错的. 那么出错的地方就在start.S部分 很明显,MPLLCON地址错误,正确 ...
- 08 自学Aruba之限制应用流量
点击返回:自学Aruba之路点击返回:自学Aruba集锦 08 自学Aruba之限制应用流量 限制带宽请查阅:点击 下文描述的步骤,主要是针对某一个SSID所用用户在使用某一个应用的时候设置共享带宽. ...