Zookeeper分布式锁案例
场景描述:
在线程高并发场景下,生成唯一的订单编号,如:
2017-10-14-20-52-33-01
年-月-日-时-分-秒-序号
Lock锁接口
package com.zookeeper.day02; /** * 锁接口 */ public interface Lock { //获取锁 public void getLock(); //释放锁 public void unLock(); }
OrderNumber订单产生的类
package com.zookeeper.day02; import java.text.SimpleDateFormat; import java.util.Date; /** * 产生订单的类 */ public class OrderNumber { private static Integer number=0; //生成订单号 public String getNumber(){ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); ++number; return simpleDateFormat.format(new Date())+" "+number; } }
ZookeeperLock
package com.zookeeper.day02; import org.I0Itec.zkclient.ZkClient; public abstract class ZookeeperLock implements Lock{ /** * 创建zkClient连接对象 */ private static final String ZK_ADDRESS="0.0.0.0:2181"; protected ZkClient zkClient=new ZkClient(ZK_ADDRESS); /** * 每一个进程在创建节点时,实际上就是获得了一把锁,如果在获取锁是发现返回值为true,代表当前没有锁,我可以使用,如果返回值为false,代表锁正在被占用,那么我只能等待 * @return */ @Override public void getLock() { //获取一把锁 if(tryLock()){ System.out.println("获取到锁资源"); }else{ //当返回值为false时,代表当前锁正在被使用,等待 waitLock(); //等待之后我得再次获取,我不再次获取我怎么能得到锁资源 getLock(); } } /** * 释放锁,zk关闭 */ @Override public void unLock() { if(zkClient!=null){ zkClient.close(); } } //获取锁资源 public abstract boolean tryLock(); //等待 public abstract void waitLock(); }
ZkLockImpl
package com.zookeeper.day02; import org.I0Itec.zkclient.IZkChildListener; import org.I0Itec.zkclient.IZkDataListener; import java.util.concurrent.CountDownLatch; public class ZkLockImpl extends ZookeeperLock{ private CountDownLatch countDownLatch=null; @Override public boolean tryLock() { try { //创建临时节点 zkClient.createEphemeral("/zkTemp"); return true; }catch (Exception ex){ return false; } } @Override public void waitLock() { //监听节点是否是删除了 IZkDataListener iZkDataListener=new IZkDataListener() { @Override public void handleDataChange(String s, Object o) throws Exception { } @Override public void handleDataDeleted(String s) throws Exception { if(countDownLatch!=null){ //释放掉 countDownLatch.countDown(); } } }; //如果已经存在zkTemp节点,就等待 if(zkClient.exists("/zkTemp")){ countDownLatch=new CountDownLatch(1); System.out.println("订单号重复,请等待================================="); try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } } } }
OrderService
package com.zookeeper.day02; /** * 订单业务处理类 */ public class OrderService implements Runnable{ private static OrderNumber orderNumber=new OrderNumber(); private Lock lock=new ZkLockImpl(); //生成订单 public void getOrderNumber(){ //同步代码块:多个线程访问同一个资源时 /*synchronized (orderNumber){ }*/ //获取锁 lock.getLock(); System.out.println("当前生成的订单编号为:"+orderNumber.getNumber()); //释放锁 lock.unLock(); } @Override public void run() { getOrderNumber(); } public static void main(String[] args) { //生成100个线程 for(int i=1;i<=100;i++){ new Thread(new OrderService()).start(); } } }