zookeeper分佈式鎖實例

<dependency>

	<groupId>com.101tec</groupId>

	<artifactId>zkclient</artifactId>

	<version>0.10</version>

</dependency>
如果有一把鎖,被多個人給競爭,此時多個人會排隊,第一個拿到鎖的人會執行,然後釋放鎖;後面的每個人都會去監聽**排在自己前面**的那個人創建的 node 上,一旦某個人釋放了鎖,排在自己後面的人就會被 zookeeper 給通知,一旦被通知了之後,就 ok 了,自己就獲取到了鎖,就可以執行代碼了。
```java
public class ZooKeeperDistributedLock {

    //private ZooKeeper zk;
    private ZkClient zk;
    private String locksRoot = "/locks";
    private String productId;
    private String waitNode;
    private String lockNode;
    private CountDownLatch latch;
    private int sessionTimeout = 30000;

    public ZooKeeperDistributedLock() {

        try {
                                         
            String address="192.168.31.187:2181,192.168.31.19:2181,192.168.31.227:2181";
            zk = new ZkClient(address, sessionTimeout, sessionTimeout);
        } catch (IOException e) {
            throw new LockException(e);
        } catch (KeeperException e) {
            throw new LockException(e);
        } catch (InterruptedException e) {
            throw new LockException(e);
        }
    }


    public void acquireDistributedLock() {
        try {
            if (this.tryLock()) {
                return;
            } else {
                waitForLock(waitNode, sessionTimeout);
                acquireDistributedLock();
            }
        } catch (KeeperException e) {
            throw new LockException(e);
        } catch (InterruptedException e) {
            throw new LockException(e);
        }
    }

    public boolean tryLock() {
        try {
 		   
            lockNode = this.client.createEphemeralSequential(locksRoot+ "/", "1");
   
            // 看看剛創建的節點是不是最小的節點
	    // locks:10000000000,10000000001,10000000002
            List<String> locks = zk.getChildren(locksRoot);
            Collections.sort(locks);
	
            if(lockNode.equals(locksRoot+"/"+ locks.get(0))){
                System.out.println(Thread.currentThread().getName() + ":獲取鎖成功");
                //如果是最小的節點,則表示取得鎖
                return true;
            }
	
            //如果不是最小的節點,找到比自己小1的節點
	  int previousLockIndex = -1;
            for(int i = 0; i < locks.size(); i++) {
		if(lockNode.equals(locksRoot + “/” + locks.get(i))) {
	         	    previousLockIndex = i - 1;
		    break;
		}
	   }
	   
	   this.waitNode = locks.get(previousLockIndex);
        } catch (KeeperException e) {
            throw new LockException(e);
        } catch (InterruptedException e) {
            throw new LockException(e);
        }
        return false;
    }

    private boolean waitForLock(String waitNode, long waitTime) throws 
        InterruptedException, KeeperException {
        Stat stat = zk.exists(locksRoot + "/" + waitNode, true);
        this.latch = new CountDownLatch(1);
        
        IZkDataListener listener = new IZkDataListener() {
 	    @Override			
            public void handleDataChange(String arg0, Object arg1) throws Exception { 			
            } 			
            @Override			
            public void handleDataDeleted(String arg0) 
                throws Exception {	            
                    System.out.println("節點被刪除了,開始搶鎖");
	            cdl.countDown();
            } 		
        };	
	
        // 完成watcher註冊		
        this.client.subscribeDataChanges(beforePath, listener);

        if (stat != null) {
            this.latch.await(waitTime, TimeUnit.MILLISECONDS);
            this.latch = null;
        }

        // 取消註冊
	this.client.unsubscribeDataChanges(beforePath, listener);
        return true;
    }

    public void unlock() {
        try {
            // 刪除/locks/10000000000節點
            // 刪除/locks/10000000001節點
            System.out.println("unlock " + lockNode);
            zk.delete(lockNode);
            System.out.println(Thread.currentThread().getName() 
                + "所有鎖釋放成功:刪除zk節點");
            lockNode = null;
            zk.close();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }
    }

    public class LockException extends RuntimeException {
        private static final long serialVersionUID = 1L;

        public LockException(String e) {
            super(e);
        }

        public LockException(Exception e) {
            super(e);
        }
    }
}
public class OrderCodeGenerator {

    private int i = 0;

    public String getOrderCode() {

	Date now = new Date();

	SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-");

	return sdf.format(now) + ++i;

    }
}

public class OrderServiceImplWithZkDis implements OrderService {

 
	private static OrderCodeGenerator org = new OrderCodeGenerator();


	private Lock lock = new ZookeeperReAbleDisLock("/LOCK_TEST");

 
	@Override

	public void createOrder() {

		String orderCode = null;

 		try {

			lock.lock();

 			orderCode = org.getOrderCode();

			//TestReLock();

			System.out.println(Thread.currentThread().getName() + "生成訂單:" + orderCode);

		} catch (Exception e) {

			e.printStackTrace();

		} finally {

			lock.unlock();

		}

	}

 
        /**
	public void TestReLock() {

		lock.lock();

		System.out.println(Thread.currentThread().getName() + "測試重入鎖成功...");

		lock.unlock();

	}
        **/ 
 

	public static void main(String[] args) {

		int num = 5;

		CyclicBarrier cyclicBarrier = new CyclicBarrier(num);
 
		for (int i = 0; i < num; i++) {

			new Thread(new Runnable() {

				@Override

				public void run() {

					OrderService orderService = new OrderServiceImplWithZkDis();

					System.out.println(Thread.currentThread().getName() + ": 我準備好了");

					try {
						cyclicBarrier.await();

					} catch (Exception e) {

						e.printStackTrace();

					}

 					orderService.createOrder();

				}

			}).start();

		}

	}

 }
Thread-2:我準備好了
Thread-3:我準備好了
Thread-1:我準備好了
Thread-5:我準備好了
Thread-4:我準備好了
Thread-4:獲取鎖成功
Thread-4生成訂單:2018-07-12-13-12-09-1
Thread-4所有鎖釋放成功:刪除ZK節點
節點刪除了,開始搶鎖
Thread-5:獲取鎖成功
Thread-5生成訂單:2018-07-12-13-12-11-2
Thread-5所有鎖釋放成功:刪除ZK節點
節點刪除了,開始搶鎖
Thread-2:獲取鎖成功
Thread-2生成訂單:2018-07-12-13-12-14-3
Thread-2所有鎖釋放成功:刪除ZK節點
節點刪除了,開始搶鎖
Thread-3:獲取鎖成功
Thread-3生成訂單:2018-07-12-13-12-17-4
Thread-3所有鎖釋放成功:刪除ZK節點
節點刪除了,開始搶鎖
Thread-1:獲取鎖成功
Thread-1生成訂單:2018-07-12-13-12-21-5
Thread-1所有鎖釋放成功:刪除ZK節點
節點刪除了,開始搶鎖

 

 

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