分布式锁
流程
- 查看目标Node是否已经创建,已经创建,那么等待锁。
- 如果未创建,创建一个临时节点zkTemp,表示已经占有锁。
- 如果创建失败,那么证明锁已经被其他线程占有了,那么同样等待锁。
- 当释放锁,节点被删除,唤醒之前等待锁的线程去争抢锁。
分布式案例
OrderNumber生成订单号类:
/*生成订单号*/ public class OrderNumber { private static int number=0; //生成订单号 public String getOrderNumber(){ SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); ++number; return simpleDateFormat.format(new Date())+" "+number; } }
OrderService订单业务逻辑类:
/*订单业务逻辑*/ public class OrderService implements Runnable { private static OrderNumber orderNumber=new OrderNumber(); public Lock lock=new ZookeeperImpl(); //生成订单 public void getnumber(){ /*synchronized (orderNumber){ System.out.println("获取的订单编号为:"+orderNumber.getOrderNumber()); }*/ lock.getLock(); //获取锁 System.out.println("获取的订单编号为:"+orderNumber.getOrderNumber()); lock.unLock(); //释放锁 } @Override public void run() { getnumber(); } public static void main(String[] args) { for (int i=0;i<100;i++){ new Thread(new OrderService()).start(); } } }
Lock接口类:
public interface Lock { //获取锁 public void getLock(); //释放锁 public void unLock(); }
ZookeeperLock实现类:
public abstract class ZookeeperLock implements Lock { //连接地址 private static final String CONNECT_ADDDR="0.0.0.0:2181"; protected ZkClient zkClient=new ZkClient(CONNECT_ADDDR); //获取锁 @Override public void getLock() { if (tryLock()){ System.out.println("获取到锁资源"); }else{ //当返回值为false的时候,代表锁已经被占用,需等待锁 waitLock(); //等待之后需再次获取锁 getLock(); } } //释放锁 @Override public void unLock() { if (zkClient!=null){ zkClient.close(); } } //获取锁资源 public abstract boolean tryLock(); //等待 public abstract void waitLock(); }
ZookeeperImpl继承类:
/*真正获取锁和释放锁*/ public class ZookeeperImpl extends ZookeeperLock { //信号量 private CountDownLatch countDownLatch=null; //获取锁资源 @Override public boolean tryLock() { try { zkClient.createEphemeral("/zkTemp"); return true; }catch (Exception e){ 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(); } } }; // 注册到zk监听中 zkClient.subscribeDataChanges("/zkTemp", iZkDataListener); //如果已经存在zkTemp节点,就等待 if(zkClient.exists("/zkTemp")){ countDownLatch=new CountDownLatch(1); System.err.println("订单号重复,请等待================================="); try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } } // 删除事件通知 zkClient.unsubscribeDataChanges("/zkTemp", iZkDataListener); } }
分布式锁思路
分布式锁使用zk,在zk上创建一个临时节点(有效期) ,使用临时节点作为锁,因为节点不允许重复。
如果能创建节点成功,生成订单号,如果创建节点失败,等待。临时节点zk关闭,释放锁,其他节点就可以重新生成订单号。