<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
通过模板方式实现
接口:
public interface ExLock {
//这个类基于Zookeeper实现分布式锁
void getLock();
/**释放锁*/
void unLock();
}
抽象模板:
package com.example.member.lock;
import org.I0Itec.zkclient.ZkClient;
import java.util.concurrent.CountDownLatch;
/**模板方法实现公共部分的编写*/
public abstract class ZookeeperAbstractLock implements ExLock{
private static final String CONNECTION="127.0.0.1:2181";
protected ZkClient zkClient = new ZkClient(CONNECTION);
public String lockPath="/lockPath";
//获取锁
public void getLock() {
//1、连接zkClient 创建一个/lock的临时节点
// 2、 如果节点创建成果,直接执行业务逻辑,如果节点创建失败,进行等待
if (tryLock()) {
System.out.println("#####成功获取锁######");
}else {
//进行等待
waitLock();
}
//3、使用事件通知监听该节点是否被删除 ,如果是,重新进入获取锁的资源
}
//创建失败 进行等待
abstract void waitLock();
abstract boolean tryLock();
//释放锁
public void unLock() {
//执行完毕 直接连接
if (zkClient != null) {
zkClient.close();
System.out.println("######释放锁完毕######");
}
}
}
实现模板的实现类:
package com.example.member.lock; import java.util.concurrent.CountDownLatch; import org.I0Itec.zkclient.IZkDataListener; public class ZookeeperDistrbuteLock extends ZookeeperAbstractLock {
CountDownLatch countDownLatch =null;
@Override boolean tryLock() { try { zkClient.createEphemeral(lockPath); System.out.println("#########获取锁######"); return true; } catch (Exception e) { // 如果失败 直接catch System.out.println("##########获取锁失败########"); return false; } } @Override void waitLock() { IZkDataListener iZkDataListener = new IZkDataListener() { // 节点被删除 public void handleDataDeleted(String arg0) throws Exception { if (countDownLatch != null) { countDownLatch.countDown(); // 计数器为0的情况,await 后面的继续执行 } } // 节点被修改 public void handleDataChange(String arg0, Object arg1) throws Exception { } }; // 监听事件通知 zkClient.subscribeDataChanges(lockPath, iZkDataListener); // 控制程序的等待 if (zkClient.exists(lockPath)) { //如果 检查出 已经被创建了 就new 然后进行等待 countDownLatch = new CountDownLatch(1); try { countDownLatch.wait(); //等待时候 就不往下走了 当为0 时候 后面的继续执行 } catch (Exception e) { // TODO: handle exception } } //后面代码继续执行 //为了不影响程序的执行 建议删除该事件监听 监听完了就删除掉 zkClient.unsubscribeDataChanges(lockPath, iZkDataListener); } }
生成订单类:
package com.example.member.lock;
import java.text.SimpleDateFormat;
import java.util.Date;
//生成订单号 时间戳
public class OrderNumGenerator {
//区分不同的订单号
private static int count = 0;
//单台服务器,多个线程 同事生成订单号
public String getNumber(){
try {
Thread.sleep(500);
} catch (Exception e) {
}
SimpleDateFormat simpt = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
return simpt.format(new Date()) + "-" + ++count; //时间戳后面加了 count
}
}
测试类:
package com.example.member.lock;
public class OrderService implements Runnable {
private OrderNumGenerator orderNumGenerator = new OrderNumGenerator(); // 定义成全局的
private ExLock lock = new ZookeeperDistrbuteLock();
public void run() {
getNumber();
}
public synchronized void getNumber() { // 加锁 保证线程安全问题 让一个线程操作
try {
lock.getLock();
String number = orderNumGenerator.getNumber();
System.out.println(Thread.currentThread().getName() + ",number" + number);
} catch (Exception e) {
} finally {
lock.unLock();
}
}
public static void main(String[] args) {
// OrderService orderService = new OrderService();
for (int i = 0; i < 100; i++) { // 开启100个线程
//模拟分布式锁的场景
new Thread(new OrderService()).start();
}
}
}