Zookeeper实现分布式锁
分布式锁的比较
![]()

zookeeper




一,curator分布式锁
1. InterProcessMutex 实现可重入锁
全局同步的可重入分布式锁,任何时刻不会有两个客户端同时持有该锁。Reentrant和JDK的ReentrantLock类似, 意味着同一个客户端(线程)在拥有锁的同时,可以多次获取,不会被阻塞。
CuratorFramework client = CuratorFrameworkFactory.newClient(ZOOKEEPERSTRING, new ExponentialBackoffRetry(1000, 3));
client.start();
lock = new InterProcessMutex(client, lockPAth);
try{//lock
lock.acquire();
// dosomething
}finlly{//unlock
lock.release();
}
2.不可重入 自定义
package com.itheima.itheimazookeeperlock.zklock;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooDefs;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
// 实现这个 Lock接口的目的就是规范。
public class ZookeeperDistributeLock implements Lock {
// zookeeper的分布式锁:是采用zookeeper的临时节点类完成,临时节点具有超时的释放的特征。
// WORKSPACE 用来隔离,其目录隔离 分类,所有的临时节点都必须放在这里统一管理。
// 锁工作区间.用来隔离,其目录隔离
private final static String WORKSPACE = "/lock-zookeeper";
// 锁的名称或者说是锁的分离
private String lockName;
// 第三方的zookeeper的客户端 zkClient / apchee curator
private CuratorFramework client;
// zookeeper的服务器,或者集群
private static final String ZOOKEEPERSERVER = "127.0.0.1:2181";
// 集群几点如下
//private static final String ZOOKEEPERSERVER = "127.0.0.01:2181,xxxxxip:2181,xxxxip:2118";
public ZookeeperDistributeLock(String lockName){//store
this.lockName = lockName;
init();
}
private void init(){
// 1: 初始化 zk客户端对象 4中
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,10);
client = CuratorFrameworkFactory.newClient(ZOOKEEPERSERVER,5000,1000,retryPolicy);
client.start();
// 2: 创建工作区--持久节点
try{
// 判断工作区间节点是否存在,不存在返回null。存在的话就抛出异常ZNodeExisteException,这样做法就是排他性。
if(client.checkExists().forPath(WORKSPACE)==null){
// 创建节点
client.create().creatingParentsIfNeeded()
//创建持久节点 CreateMode.PERSISTENT
.withMode(CreateMode.PERSISTENT)
.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
.forPath(WORKSPACE);
}
}catch(Exception ex){
ex.printStackTrace();
}
}
@Override
public void lock() {
while (true){
// 临时节点的创建
String lockPath = WORKSPACE + "/" + lockName;
try {
// 判断工作区间节点是否存在,不存在返回null。存在的话就抛出异常ZNodeExisteException,这样做法就是排他性。
if(client.checkExists().forPath(lockPath)==null){
// 创建节点
client.create().creatingParentsIfNeeded()
//创建临时节点 CreateMode.PERSISTENT
.withMode(CreateMode.EPHEMERAL)
.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
.forPath(lockPath);
// 1: zookeeper 节点具有排他性
// 2:但是没有阻塞的,怎么解决
System.out.println("get lock success .........");
return;
}else{
// 其他的进程,全部在这里阻塞。
listenerrWait();
}
}catch (Exception ex){
// 为什么捕获隐藏,就是排他性
try{
listenerrWait();
}catch(Exception ex2){
ex2.printStackTrace();
}
}
}
}
// 监听 ---所有请求
public void listenerrWait() throws Exception{
// 阻塞类
final CountDownLatch countDownLatch = new CountDownLatch(1);
// 初始化话子节点监听器
PathChildrenCache pathChildrenCache = new PathChildrenCache(client, WORKSPACE, true);
pathChildrenCache.start();
// 定义监听器,这个监听器就监听WORKSPACE的目录的变化情况,如果一定放生任何的改变,就会出发zk的watcher机制
pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
@Override
public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent event) throws Exception {
System.out.println(event.getType().name());
if(event.getType().equals(PathChildrenCacheEvent.Type.CHILD_REMOVED)){
System.out.println("子节点删除了.....开始释放锁....");
// 释放锁,通知别的进程来获取锁
countDownLatch.countDown();
}
}
});
//类自旋的东西
// 阻塞进程,不往下执行 await
countDownLatch.await(5, TimeUnit.SECONDS);
}
@Override
public void unlock() {
// 临时节点的创建
String lockPath = WORKSPACE + "/" + lockName;
try{
if (client.checkExists().forPath(lockPath)!=null) {
client.delete().forPath(lockPath);
System.out.println("释放锁..........");
}
}catch(Exception ex){
ex.printStackTrace();
}
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
@Override
public boolean tryLock() {
return false;
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public Condition newCondition() {
return null;
}
}
x
169
1
package com.itheima.itheimazookeeperlock.zklock;2
3
import org.apache.curator.RetryPolicy;4
import org.apache.curator.framework.CuratorFramework;5
import org.apache.curator.framework.CuratorFrameworkFactory;6
import org.apache.curator.framework.recipes.cache.PathChildrenCache;7
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;8
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;9
import org.apache.curator.retry.ExponentialBackoffRetry;10
import org.apache.zookeeper.CreateMode;11
import org.apache.zookeeper.ZooDefs;12
13
import java.util.concurrent.CountDownLatch;14
import java.util.concurrent.TimeUnit;15
import java.util.concurrent.locks.Condition;16
import java.util.concurrent.locks.Lock;17
18
// 实现这个 Lock接口的目的就是规范。19
public class ZookeeperDistributeLock implements Lock {20
21
// zookeeper的分布式锁:是采用zookeeper的临时节点类完成,临时节点具有超时的释放的特征。22
// WORKSPACE 用来隔离,其目录隔离 分类,所有的临时节点都必须放在这里统一管理。23
24
// 锁工作区间.用来隔离,其目录隔离25
private final static String WORKSPACE = "/lock-zookeeper";26
27
// 锁的名称或者说是锁的分离28
private String lockName;29
30
// 第三方的zookeeper的客户端 zkClient / apchee curator31
private CuratorFramework client;32
33
// zookeeper的服务器,或者集群34
private static final String ZOOKEEPERSERVER = "127.0.0.1:2181";35
// 集群几点如下36
//private static final String ZOOKEEPERSERVER = "127.0.0.01:2181,xxxxxip:2181,xxxxip:2118";37
38
public ZookeeperDistributeLock(String lockName){//store39
this.lockName = lockName;40
init();41
}42
43
44
private void init(){45
// 1: 初始化 zk客户端对象 4中46
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,10);47
client = CuratorFrameworkFactory.newClient(ZOOKEEPERSERVER,5000,1000,retryPolicy);48
client.start();49
50
// 2: 创建工作区--持久节点51
try{52
// 判断工作区间节点是否存在,不存在返回null。存在的话就抛出异常ZNodeExisteException,这样做法就是排他性。53
if(client.checkExists().forPath(WORKSPACE)==null){54
55
// 创建节点56
client.create().creatingParentsIfNeeded()57
//创建持久节点 CreateMode.PERSISTENT58
.withMode(CreateMode.PERSISTENT)59
.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)60
.forPath(WORKSPACE);61
}62
}catch(Exception ex){63
ex.printStackTrace();64
}65
}66
67
68
69
70
public void lock() {71
while (true){72
// 临时节点的创建73
String lockPath = WORKSPACE + "/" + lockName;74
try {75
// 判断工作区间节点是否存在,不存在返回null。存在的话就抛出异常ZNodeExisteException,这样做法就是排他性。76
if(client.checkExists().forPath(lockPath)==null){77
// 创建节点78
client.create().creatingParentsIfNeeded()79
//创建临时节点 CreateMode.PERSISTENT80
.withMode(CreateMode.EPHEMERAL)81
.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)82
.forPath(lockPath);83
// 1: zookeeper 节点具有排他性84
// 2:但是没有阻塞的,怎么解决85
System.out.println("get lock success .........");86
return;87
}else{88
// 其他的进程,全部在这里阻塞。89
listenerrWait();90
}91
}catch (Exception ex){92
// 为什么捕获隐藏,就是排他性93
try{94
listenerrWait();95
}catch(Exception ex2){96
ex2.printStackTrace();97
}98
}99
}100
}101
102
103
104
// 监听 ---所有请求105
public void listenerrWait() throws Exception{106
107
// 阻塞类108
final CountDownLatch countDownLatch = new CountDownLatch(1);109
110
// 初始化话子节点监听器111
PathChildrenCache pathChildrenCache = new PathChildrenCache(client, WORKSPACE, true);112
pathChildrenCache.start();113
114
// 定义监听器,这个监听器就监听WORKSPACE的目录的变化情况,如果一定放生任何的改变,就会出发zk的watcher机制115
pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {116
117
public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent event) throws Exception {118
System.out.println(event.getType().name());119
if(event.getType().equals(PathChildrenCacheEvent.Type.CHILD_REMOVED)){120
System.out.println("子节点删除了.....开始释放锁....");121
// 释放锁,通知别的进程来获取锁122
countDownLatch.countDown();123
}124
}125
});126
//类自旋的东西127
// 阻塞进程,不往下执行 await128
countDownLatch.await(5, TimeUnit.SECONDS);129
}130
131
132
133
public void unlock() {134
// 临时节点的创建135
String lockPath = WORKSPACE + "/" + lockName;136
try{137
if (client.checkExists().forPath(lockPath)!=null) {138
client.delete().forPath(lockPath);139
System.out.println("释放锁..........");140
}141
}catch(Exception ex){142
ex.printStackTrace();143
}144
}145
146
147
148
149
public void lockInterruptibly() throws InterruptedException {150
151
}152
153
154
public boolean tryLock() {155
return false;156
}157
158
159
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {160
return false;161
}162
163
164
165
public Condition newCondition() {166
return null;167
}168
}169

浙公网安备 33010602011771号