1. 程式人生 > >zk 分散式共享鎖小Demo

zk 分散式共享鎖小Demo


public class DistributedClientLock {
    

    // 會話超時
    private static final int SESSION_TIMEOUT = 2000;
    // zookeeper叢集地址
    private String hosts = "192.168.203.129:2181,192.168.203.130:2181,192.168.203.131:2181";
    private String groupNode = "locks";
    private String subNode = "sub";
    private boolean haveLock = false;

    private ZooKeeper zk;
    // 記錄自己建立的子節點路徑
    private volatile String thisPath;

    /**
     * 連線zookeeper
     */
    public void connectZookeeper() throws Exception {
        zk = new ZooKeeper(hosts, SESSION_TIMEOUT, new Watcher() {
            public void process(WatchedEvent event) {
                try {

                    // 判斷事件型別,此處只處理子節點變化事件
                    if (event.getType() == EventType.NodeChildrenChanged && event.getPath().equals("/" + groupNode)) {
                        //獲取子節點,並對父節點進行監聽
                        List<String> childrenNodes = zk.getChildren("/" + groupNode, true);
                        String thisNode = thisPath.substring(("/" + groupNode + "/").length());
                        // 去比較是否自己是最小id
                        Collections.sort(childrenNodes);
                        System.out.println("thisNode: " + thisNode);
                        if (childrenNodes.indexOf(thisNode) == 0) {
                            //訪問共享資源處理業務,並且在處理完成之後刪除鎖
                            doSomething();
                            
                            //重新註冊一把新的鎖
                            thisPath = zk.create("/" + groupNode + "/" + subNode, null, Ids.OPEN_ACL_UNSAFE,
                                    CreateMode.EPHEMERAL_SEQUENTIAL);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        // 1、程式一進來就先註冊一把鎖到zk上
        thisPath = zk.create("/" + groupNode + "/" + subNode, null, Ids.OPEN_ACL_UNSAFE,
                CreateMode.EPHEMERAL_SEQUENTIAL);
        System.out.println("thisPath: " + thisPath);
        // wait一小會,便於觀察
        Thread.sleep(new Random().nextInt(1000));

        // 從zk的鎖父目錄下,獲取所有子節點,並且註冊對父節點的監聽
        List<String> childrenNodes = zk.getChildren("/" + groupNode, true);

        //如果爭搶資源的程式就只有自己,則可以直接去訪問共享資源 
        if (childrenNodes.size() == 1) {
            doSomething();
            thisPath = zk.create("/" + groupNode + "/" + subNode, null, Ids.OPEN_ACL_UNSAFE,
                    CreateMode.EPHEMERAL_SEQUENTIAL);
        }
    }

    /**
     * 處理業務邏輯,並且在最後釋放鎖
     */
    private void doSomething() throws Exception {
        try {
            System.out.println("gain lock: " + thisPath);
            Thread.sleep(2000);
            // do something
        } finally {
            System.out.println("finished: " + thisPath);
            // 錕斤拷thisPath刪錕斤拷, 錕斤拷錕斤拷thisPath錕斤拷client錕斤拷錕斤拷錕酵ㄖ�
            // 錕潔當錕斤拷錕酵鳳拷錕斤拷
            zk.delete(this.thisPath, -1);
        }
    }

    public static void main(String[] args) throws Exception {
        DistributedClientLock dl = new DistributedClientLock();
        dl.connectZookeeper();
        Thread.sleep(Long.MAX_VALUE);
    }

    
}