ZK 分布式锁
通俗的解释:类似与生活中的排队,所有人都向前一个人看(前面有没有人,他在未获得锁之前有有没走,走了就在向前看一个,一直观察这个,直至得到锁),如果自己的前面没有人,那么自己是第一个(获得锁),获得锁的人,事没做完,锁是不会被解开的,其他人只能等待,直至结束,锁解开,下一个人获得锁
百度了张图(侵权请告知)
public class runTest { static int TASK_SUM_COUNTS=10; static CountDownLatch threadLatch = new CountDownLatch(TASK_SUM_COUNTS); public static void main(String a[]) throws Exception { //运行10个线程,模拟10人排队 for (int i = 0; i < TASK_SUM_COUNTS; i++) { new Thread(new Runnable() { public void run() { try { new MyThread(new Doing() { public void todo() { System.out.println("----要做的事"); //处理完一个人的,count减1 threadLatch.countDown(); } }); } catch (Exception e) { System.out.println("--发生了错误"); } } }).start(); } //等待10个线程运行完毕(count直至到0,程序才会向下执行,否则在此等待) threadLatch.await(); System.out.println("----所有任务执行完毕!"); } }
public class MyThread extends UnicastRemoteObject implements Watcher { private String PUB_PATH = "/Dis"; private String SUB_PATH = PUB_PATH + "/task"; private String url = "localhost:11102"; private CountDownLatch zkLatch; private ZooKeeper zooKeeper; private Doing doing; //单个文件名 文件名是:task0001、task0002..... private String dirS; public MyThread(Doing doing) throws Exception { this.doing = doing; zkLatch = new CountDownLatch(1); zooKeeper = new ZooKeeper(url, 2000, this); //等待连上ZK zkLatch.await(); getLock(); } //创建节点并分配锁 private void getLock() throws KeeperException, InterruptedException { if (zooKeeper.exists(PUB_PATH, false) == null) { //如果目录不存在,创建目录 zooKeeper.create(PUB_PATH, "存储队列目录".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } //创建序列化的短期文件 dirS = zooKeeper.create(SUB_PATH, "这里是内容,根据业务填,不填传null".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); if (checkFirst()) { //获取锁 doing.todo(); } } //检测我是否可以拿到锁 private boolean checkFirst() throws KeeperException, InterruptedException { List<String> children = zooKeeper.getChildren(PUB_PATH, true); //排序 Collections.sort(children); //判断该文件在集合中的第几位 int index = children.indexOf(dirS.substring(PUB_PATH.length() + 1)); switch (index) { case -1: System.out.println("----该文件已不存在了"); return false; case 0: System.out.println("----我是第一位,我可以拿到锁"); return true; default: //观察前一位 try { //这里的try catch是为了在getData时,文件不存在会抛出异常,如果文件不存在,那么就观察再前一位,这里采用递归查找 String watcherFile = PUB_PATH + children.get(index - 1); System.out.println("-----给我之前的文件:" + watcherFile + " 增加Watcher观察"); zooKeeper.getData(watcherFile, this, new Stat()); return false; } catch (Exception e) { System.out.println("----前面那位居然失踪了。。。我再向前看一位。。哈哈哈"); return checkFirst(); } } } public void process(WatchedEvent event) { if (event.getState() == Event.KeeperState.SyncConnected) { //连上了ZK,count减1,使程序继续运行 zkLatch.countDown(); } }