Zookeeper實現分佈式鎖

Zookeeper實現分佈式鎖
共享鎖

分佈式鎖

**
 * 實現分佈式環境下同步鎖的實現
 *
 * @author hao.wang
 * @date 2017/1/20 15:43
 */
public class DistributeLockDemo implements Watcher {

    ZooKeeper zk = null; //zookeeper原生api去實現一個分佈式鎖

    private String root = "/locks";

    private String myZonode; //表示當前獲取到的鎖名稱-也就是節點名稱

    private String waitNode; // 表示當前等待的節點

    private CountDownLatch latch;

    //server鏈接字符串
    private static final String CONNECTION_STRING = "139.199.182.26:5000,139.199.182.26:5001,139.199.182.26:5002";

    private static final int SESSION_TIMEOUT = 5000; //超時時間

    /**
     * 構造函數初始化
     *
     * @param config 表示zookeeper連接串
     */
    public DistributeLockDemo(String config) {
        try {
            zk = new ZooKeeper(config, SESSION_TIMEOUT, this);
            Stat stat = zk.exists(root, false); //判斷是不是已經存在locks節點,不需要監聽root節點
            if (stat == null) { //如果不存在,則創建根節點
                zk.create(root, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void process(WatchedEvent event) {
        System.out.println(event.getPath());
        if (this.latch != null) { //如果計數器不爲空話話,釋放計數器鎖

            this.latch.countDown();
        }
    }

    /**
     * 獲取鎖的方法
     */
    public void lock() {
        if (tryLock()) {
            System.out.println("Thread " + Thread.currentThread().getName() + " - hold lock!");
            return;
        }
        try {
            waitLock(waitNode, SESSION_TIMEOUT);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //等待並獲取鎖
    }

    /**
     * 釋放鎖操作的方法
     */
    public void unlock() {
        System.out.println("UnLock = " + myZonode);
        try {
            zk.delete(myZonode, -1);
            myZonode = null;
            zk.close();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }

    }

    private boolean tryLock() {
        String splitStr = "lock_"; //lock_0000000001
        try {
            //創建一個有序的臨時節點,賦值給myznode
            myZonode = zk.create(root + "/" + splitStr, new byte[0],
                    ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
            System.out.println(myZonode + " 創建成功");
            List<String> subNodes = zk.getChildren(root, false);
            Collections.sort(subNodes); //講所有的子節點排序
            if (myZonode.equals(root + "/" + subNodes.get(0))) {
                //當前客戶端創建的臨時有序節點是locks下節點中的最小的節點,表示當前的客戶端能夠獲取到鎖
                return true;
            }
            //否則的話,監聽比自己小的節點 locks/lock_0000000003
            String subMyZnode = myZonode.substring((myZonode.lastIndexOf("/") + 1));
            waitNode = subNodes.get(Collections.binarySearch(subNodes, subMyZnode) - 1);// 獲取比當前節點小的節點
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return false;
    }

    private boolean waitLock(String lower, long waitTime) throws KeeperException, InterruptedException {
        Stat stat = zk.exists(root + "/" + lower, true); //獲取節點狀態,並添加監聽
        if (stat != null) {
            System.out.println("Thread " + Thread.currentThread().getName() + " waiting for" + root + " /" + lower);
            this.latch = new CountDownLatch(1); //實例化計數器,讓當前的線程等待
            this.latch.await(waitTime, TimeUnit.MILLISECONDS);
            this.latch = null;
        }
        return true;
    }

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        Semaphore semaphore = new Semaphore(10);
        for (int i = 0; i < 10; i++) {
            Runnable runnable = () -> { //lambda的一種用法,在java8裏面有。
                try {
                    semaphore.acquire();
                    DistributeLockDemo distributeLockDemo = new DistributeLockDemo(CONNECTION_STRING);
                    distributeLockDemo.lock();
                    //業務代碼
                    System.out.println(Thread.currentThread().getName() +"開始執行業務代碼");

                    distributeLockDemo.unlock();
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            };
            executorService.execute(runnable);
        }
        executorService.shutdown();


    }


}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章