使用zookeeper(以下称为zk)实现分布式锁主要是因为,使用了zk节点操作的原子性。
如下:
https://zookeeper.apache.org/doc/r3.5.7/zookeeperOver.html
The data stored at each znode in a namespace is read and written atomically. Reads get all the data bytes associated with a znode and a write replaces all the data. Each node has an Access Control List (ACL) that restricts who can do what.
Atomicity - Updates either succeed or fail. No partial results.
ps:也是通过翻译看的。。。至于zk的其他东西,在这不详细说了,只是说说基本的使用。有时间整理一套zk的内容。下面直接上代码。
1.首先,你需要有一个zk。如何安装zk,自行百度。
2.演示一下,没有分布式锁的情况下的代码(这里一生成一个唯一id为业务场景)。
package com.peter;
/**
* 业务场景
* @author Peter
*/
public class Main {
//模拟id
public static int ID = 0;
public static void main(String[] args) {
System.out.println("####生成唯一ID####");
for (int i = 0; i < 10; i++) {
new Thread(() -> {
ID++;
System.out.println("当前线程:" + Thread.currentThread().getName() + ";当前id:" + ID);
}).start();
}
}
}
输出结果
####生成唯一ID####
当前线程:Thread-0;当前id:2
当前线程:Thread-2;当前id:3
当前线程:Thread-3;当前id:4
当前线程:Thread-1;当前id:2
当前线程:Thread-4;当前id:5
当前线程:Thread-5;当前id:6
当前线程:Thread-6;当前id:7
当前线程:Thread-7;当前id:9
当前线程:Thread-8;当前id:8
当前线程:Thread-9;当前id:10
出现了id重复的情况,接下来使用zk进行处理
3.zk锁代码
3.1 ZkAbstractLock
package com.peter.zk;
import org.I0Itec.zkclient.ZkClient;
import java.util.concurrent.locks.Lock;
/**
* 抽象zk分布式锁
*
* @author Peter
*/
public abstract class ZkAbstractLock implements Lock {
// zk连接地址
private static final String ZK_ADDRESS = "127.0.0.1:2181";
// 创建zk连接
protected ZkClient zkClient = new ZkClient(ZK_ADDRESS);
protected static final String PATH = "/peterlock";
public void lock() {
if (tryLock()) {
System.out.println("####线程:" + Thread.currentThread().getId() + ",获取lock####");
} else {
waitLock();
lock();
}
}
public void unlock() {
if (zkClient != null) {
zkClient.close();
System.out.println("&&&&线程:" + Thread.currentThread().getId() + ",释放锁资源&&&&");
}
}
protected abstract void waitLock();
}
3.2 ZkDistributLock
package com.peter.zk;
import org.I0Itec.zkclient.IZkDataListener;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
/**
* zk分布式锁
*
* @author Peter
* @date 2020-03-07 15:46
*/
public class ZkDistributLock extends ZkAbstractLock {
private CountDownLatch countDownLatch = null;
protected void waitLock() {
IZkDataListener izkDataListener = new IZkDataListener() {
public void handleDataDeleted(String path) {
// 唤醒被等待的线程
if (countDownLatch != null) {
countDownLatch.countDown();
}
}
public void handleDataChange(String path, Object data) {
}
};
// 注册事件
zkClient.subscribeDataChanges(PATH, izkDataListener);
if (zkClient.exists(PATH)) {
countDownLatch = new CountDownLatch(1);
try {
countDownLatch.await();
} catch (Exception e) {
e.printStackTrace();
}
}
// 删除监听
zkClient.unsubscribeDataChanges(PATH, izkDataListener);
}
public boolean tryLock() {
try {
zkClient.createEphemeral(PATH);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public boolean tryLock(long time, TimeUnit unit) {
return false;
}
public Condition newCondition() {
return null;
}
public void lockInterruptibly() {
}
}
3.3
package com.peter;
import com.peter.zk.ZkDistributLock;
import java.util.concurrent.locks.Lock;
/**
* 业务场景
*
* @author Peter
* @date 2020-03-07 15:01
*/
public class Main {
//模拟id
public static int ID = 0;
public static void main(String[] args) {
System.out.println("####生成唯一ID####");
for (int i = 0; i < 30; i++) {
new Thread(() -> {
Lock lock = new ZkDistributLock();
try {
lock.lock();
Thread.sleep(100);
ID++;
lock.unlock();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("当前线程:" + Thread.currentThread().getName() + ";当前id:" + ID);
}).start();
}
}
}
输出结果:
####线程:35,获取lock####
&&&&线程:35,释放锁资源&&&&
当前线程:Thread-23;当前id:1
####线程:23,获取lock####
&&&&线程:23,释放锁资源&&&&
当前线程:Thread-11;当前id:2
####线程:37,获取lock####
&&&&线程:37,释放锁资源&&&&
当前线程:Thread-25;当前id:3
####线程:33,获取lock####
&&&&线程:33,释放锁资源&&&&
当前线程:Thread-21;当前id:4
####线程:28,获取lock####
&&&&线程:28,释放锁资源&&&&
当前线程:Thread-16;当前id:5
####线程:29,获取lock####
&&&&线程:29,释放锁资源&&&&
当前线程:Thread-17;当前id:6
####线程:13,获取lock####
&&&&线程:13,释放锁资源&&&&
当前线程:Thread-1;当前id:7
####线程:39,获取lock####
&&&&线程:39,释放锁资源&&&&
当前线程:Thread-27;当前id:8
####线程:41,获取lock####
&&&&线程:41,释放锁资源&&&&
当前线程:Thread-29;当前id:9
####线程:27,获取lock####
&&&&线程:27,释放锁资源&&&&
当前线程:Thread-15;当前id:10
####线程:14,获取lock####
&&&&线程:14,释放锁资源&&&&
当前线程:Thread-2;当前id:11
####线程:38,获取lock####
&&&&线程:38,释放锁资源&&&&
当前线程:Thread-26;当前id:12
####线程:22,获取lock####
&&&&线程:22,释放锁资源&&&&
当前线程:Thread-10;当前id:13
####线程:32,获取lock####
&&&&线程:32,释放锁资源&&&&
当前线程:Thread-20;当前id:14
####线程:31,获取lock####
&&&&线程:31,释放锁资源&&&&
当前线程:Thread-19;当前id:15
####线程:30,获取lock####
&&&&线程:30,释放锁资源&&&&
当前线程:Thread-18;当前id:16
####线程:17,获取lock####
&&&&线程:17,释放锁资源&&&&
当前线程:Thread-5;当前id:17
####线程:34,获取lock####
&&&&线程:34,释放锁资源&&&&
当前线程:Thread-22;当前id:18
####线程:19,获取lock####
&&&&线程:19,释放锁资源&&&&
当前线程:Thread-7;当前id:19
####线程:40,获取lock####
&&&&线程:40,释放锁资源&&&&
当前线程:Thread-28;当前id:20
####线程:15,获取lock####
&&&&线程:15,释放锁资源&&&&
当前线程:Thread-3;当前id:21
####线程:26,获取lock####
&&&&线程:26,释放锁资源&&&&
当前线程:Thread-14;当前id:22
####线程:16,获取lock####
&&&&线程:16,释放锁资源&&&&
当前线程:Thread-4;当前id:23
####线程:20,获取lock####
&&&&线程:20,释放锁资源&&&&
当前线程:Thread-8;当前id:24
####线程:21,获取lock####
&&&&线程:21,释放锁资源&&&&
当前线程:Thread-9;当前id:25
####线程:25,获取lock####
&&&&线程:25,释放锁资源&&&&
当前线程:Thread-13;当前id:26
####线程:12,获取lock####
&&&&线程:12,释放锁资源&&&&
当前线程:Thread-0;当前id:27
####线程:36,获取lock####
&&&&线程:36,释放锁资源&&&&
当前线程:Thread-24;当前id:28
####线程:24,获取lock####
&&&&线程:24,释放锁资源&&&&
当前线程:Thread-12;当前id:29
####线程:18,获取lock####
&&&&线程:18,释放锁资源&&&&
当前线程:Thread-6;当前id:30