zookeeper实现分布式锁(代码)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_29493353/article/details/85707154
public class zkDemo implements Watcher {
    private static final Logger LOG;
    static {
        //Keep these two lines together to keep the initialization order explicit
        LOG = LoggerFactory.getLogger(ZooKeeper.class);
    }
    private static final CountDownLatch cdl = new CountDownLatch(1);
//    static  ZooKeeper zk;
    static final List<String> recode = new ArrayList<String>();

    boolean flag = true;

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    static Object ob = new Object();

    public static void main(String[] args) throws IOException {
        ExecutorService es = Executors.newFixedThreadPool( 10 );
        List<Future<String>> li = new ArrayList<Future<String>>();
        for (int i=0;i<10;i++){
            final String num = i +"";
            Future<String> fv = es.submit( new Callable<String>() {
                @Override
                public String call() throws IOException, KeeperException, InterruptedException {
                    ZooKeeper zk = new ZooKeeper("192.168.0.170:2181", 5000, new zkDemo());
                    String path = zk.create("/lock/test-", "456".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
                    String small_path = get_smaller_node(path);
                    if (small_path == null){
                        System.out.println( num+"由于不是第一次注册,立马获取了锁");
                    }else{
                        //先不注册wather判断存不存在
                        if(zk.exists( small_path, false ) == null){
                            System.out.println( num+"获取了锁,path为:"+ path+"。第一次判断");
                            synchronized (recode){
                                recode.add( num );
                            }
                            //等待所有的都注册好之后再退出 然后关闭session
                            while(recode.size() < 10){
                                //这个是多线程的interupt
                                Thread.yield();
                            }
                            System.out.println( recode );
                        }else{
                            boolean flag = true;
                            zkDemo de = new zkDemo();
                            //注册一个watcher,当de的全局变量变成false的时候说明上一个节点被删除了
                            System.out.println( num+"开始判断先前一个节点"+small_path+"是否存在" );
                            //实验证明当一个节点删除之后,de的全局变量不变
                            System.out.println( de );
                            Stat st = zk.exists( small_path, de );
                            synchronized (recode){
                                recode.add( num );
                            }
                            boolean flag_result = true;
                            while (flag_result) {
                                flag_result = de.isFlag();
                                Thread.yield();
                            }
                            //这个方式不好的是万一一开始上一个节点删除之前 本节点还没注册好watcher就炸了
                            System.out.println( num+"获取了锁,path为:"+ path+"。watcher被动获取");
                            /**
                             * start do your job
                             */


                            /**
                             * end your job
                             */
                        }

                    }
                    zk.close();
                    return num;
                }

                private String get_smaller_node(String path){
                    int num = Integer.parseInt(path.split( "-" )[1])-1;
                    if (num < 0){
                        return null;
                    }else{
                        String a = num +"";
                        String result = "/lock/test-";
                        for(int i =0;i<10-a.length();i++){
                            result = result+"0";
                        }
                        result = result + a;
                        return result;
                    }
                }
            } );
            li.add( fv );
        }
        for (Future<String> fv : li){
            try {
                System.out.println(fv.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        es.shutdown();

    }

    //监听到事件时进行处理
    public void process(WatchedEvent event) {
//        LOG.info( "事件的路径为:" +event.getPath() );
//        if (Watcher.Event.KeeperState.SyncConnected == event.getState()) {
//            cdl.countDown();
//        }
//        if (event.getType() == Event.EventType.NodeCreated) {
//            System.out.println( event.getPath() + "创建了");
//        }
//        if (event.getType() == Event.EventType.NodeDataChanged) {
//            System.out.println( event.getPath() + "数据改变了");
//            System.out.println( event.getState());
//        }
          if (event.getType() == Event.EventType.NodeDeleted){
              System.out.println( "节点被删除:"+event.getPath() );
              System.out.println( this );
              this.setFlag(false);

          }

    }
}

打印结果:

2开始判断先前一个节点/lock/test-0000000287是否存在
zkDemo@54c96913
4开始判断先前一个节点/lock/test-0000000286是否存在
zkDemo@350bad47
8开始判断先前一个节点/lock/test-0000000283是否存在
zkDemo@5585bfef
0开始判断先前一个节点/lock/test-0000000285是否存在
zkDemo@4462917e
5开始判断先前一个节点/lock/test-0000000284是否存在
zkDemo@60e57dfb
1开始判断先前一个节点/lock/test-0000000282是否存在
zkDemo@4221aac4
3开始判断先前一个节点/lock/test-0000000288是否存在
zkDemo@7d2b165d
7开始判断先前一个节点/lock/test-0000000280是否存在
zkDemo@11964ed6
9开始判断先前一个节点/lock/test-0000000281是否存在
zkDemo@3cac98cf
6获取了锁,path为:/lock/test-0000000280。第一次判断
[4, 0, 8, 3, 7, 5, 1, 2, 9, 6]
节点被删除:/lock/test-0000000280
zkDemo@11964ed6
7获取了锁,path为:/lock/test-0000000281。watcher被动获取
节点被删除:/lock/test-0000000281
zkDemo@3cac98cf
9获取了锁,path为:/lock/test-0000000282。watcher被动获取
节点被删除:/lock/test-0000000282
zkDemo@4221aac4
1获取了锁,path为:/lock/test-0000000283。watcher被动获取
节点被删除:/lock/test-0000000283
zkDemo@5585bfef
8获取了锁,path为:/lock/test-0000000284。watcher被动获取
节点被删除:/lock/test-0000000284
zkDemo@60e57dfb
5获取了锁,path为:/lock/test-0000000285。watcher被动获取
节点被删除:/lock/test-0000000285
zkDemo@4462917e
0获取了锁,path为:/lock/test-0000000286。watcher被动获取
节点被删除:/lock/test-0000000286
zkDemo@350bad47
0
1
4获取了锁,path为:/lock/test-0000000287。watcher被动获取
节点被删除:/lock/test-0000000287
zkDemo@54c96913
2获取了锁,path为:/lock/test-0000000288。watcher被动获取
节点被删除:/lock/test-0000000288
zkDemo@7d2b165d
3获取了锁,path为:/lock/test-0000000289。watcher被动获取
2
3
4
5
6
7
8

说明:本例用线程池模拟了分布式锁的使用

遇到的问题:

1.获取本节点上一个节点的计算方式(zk临时自增节点的path规范)

2.多线程while循环导致其他线程卡死。可以用 Thread.yield();将当前的线程锁交出(可能成功也可能失败)。

猜你喜欢

转载自blog.csdn.net/qq_29493353/article/details/85707154