zokeeper实现分布式锁

316 阅读1分钟

基本思路:

1.每次请求都在某个根节点下创建一个子节点
2.判断当前请求的节点是否是最小的一个节点。
2.1如果是,说明加锁成功,继续业务;如果不是,说明获取锁失败
2.2如果不是,获取比当前小一个的节点(假设为A),监听A这个节点的状态
2.3当A这个节点的状态为被删除时,说明上个业务处理完毕,则当前获得锁

代码实现

private static CountDownLatch countDownLatch = new CountDownLatch(1);

    public static void main(String[] args) throws Exception {
        ExponentialBackoffRetry retry = new ExponentialBackoffRetry(1000, 3);
        CuratorFramework client = CuratorFrameworkFactory.builder()
                .connectString("localhost:2181,localhost:2182,localhost:2183")
                .sessionTimeoutMs(30000)
                .connectionTimeoutMs(30000)
                .retryPolicy(retry)
                //.namespace("distributedLock") //每个业务对应的独立命名空间
                .build();
        client.start();
        Thread.sleep(1000);
        client.delete().deletingChildrenIfNeeded().forPath("/distributedLock");
        String myZnode = client.create()
                .creatingParentContainersIfNeeded()
                .withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
                .withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
                .forPath("/distributedLock/locktest&subject1_lock_", new byte[0]);
        client.getChildren().forPath("/distributedLock").forEach(e -> System.out.println("------------------\r\n"+e));
        String mySecondZnode = client.create()
                .creatingParentContainersIfNeeded()
                .withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
                .withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
                .forPath("/distributedLock/locktest&subject1_lock_", new byte[1]);
        ArrayList<String> list = new ArrayList<>();
        client.getChildren().forPath("/distributedLock").forEach(e -> {
            list.add(e);
        });
        Collections.sort(list);
        //获取比自己小一个的节点,并监听这个节点,当这个节点被删除池,则当前节点可以获得锁
        String substring = mySecondZnode.substring(mySecondZnode.lastIndexOf("/") + 1);
        String waitNode = list.get(Collections.binarySearch(list, substring) - 1);
        Stat stat = client.checkExists().forPath("/distributedLock/"+waitNode);
        if (stat != null){
            NodeCache cache = new NodeCache(client, "/distributedLock/"+waitNode);
            NodeCacheListener listener = () -> {
                ChildData data = cache.getCurrentData();
                if (null != data) {
                    System.out.println("节点数据:" + new String(cache.getCurrentData().getData()));
                } else {
                    System.out.println("节点被删除!");
                    countDownLatch.countDown();
                }
            };
            cache.getListenable().addListener(listener);
            cache.start();
            Runnable runnable = () -> {
                try {
                    Thread.sleep(60000);
                    client.delete().withVersion(-1).forPath("/distributedLock/"+waitNode);
                    System.out.println("=============节点删除成功============");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            };
            new Thread(runnable).start();
            countDownLatch.await();
            cache.close();
            client.close();
            System.out.println("---------------哈哈哈哈,我是第一,我获得锁了-------------------");
        }

pom依赖见github(mysql读写分离和zookeeper锁都写在一个项目里面,懒得分开了):github.com/zhankun/mys…