ZooKeeper分佈式鎖的實現原理

package com.roncoo.eshop.cache.zk;

import java.util.concurrent.CountDownLatch;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

/**
 * ZooKeeperSession
 * @author Administrator
 *
 */
public class ZooKeeperSession {
	
	private static CountDownLatch connectedSemaphore = new CountDownLatch(1);
	
	private ZooKeeper zookeeper;

	public ZooKeeperSession() {
		// 去連接zookeeper server,創建會話的時候,是異步去進行的
		// 所以要給一個監聽器,說告訴我們什麼時候纔是真正完成了跟zk server的連接
		try {
			this.zookeeper = new ZooKeeper(
					"192.168.31.187:2181,192.168.31.19:2181,192.168.31.227:2181", 
					50000, 
					new ZooKeeperWatcher());
			// 給一個狀態CONNECTING,連接中
			System.out.println(zookeeper.getState());
			
			try {
				// CountDownLatch
				// java多線程併發同步的一個工具類
				// 會傳遞進去一些數字,比如說1,2 ,3 都可以
				// 然後await(),如果數字不是0,那麼久卡住,等待
				
				// 其他的線程可以調用coutnDown(),減1
				// 如果數字減到0,那麼之前所有在await的線程,都會逃出阻塞的狀態
				// 繼續向下運行
				
				connectedSemaphore.await();
			} catch(InterruptedException e) {
				e.printStackTrace();
			}

			System.out.println("ZooKeeper session established......");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 獲取分佈式鎖
	 * @param productId
	 */
	public void acquireDistributedLock(Long productId) {
		String path = "/product-lock-" + productId;
	
		try {
			zookeeper.create(path, "".getBytes(), 
					Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
			System.out.println("success to acquire lock for product[id=" + productId + "]");  
		} catch (Exception e) {
			// 如果那個商品對應的鎖的node,已經存在了,就是已經被別人加鎖了,那麼就這裏就會報錯
			// NodeExistsException
			int count = 0;
			while(true) {
				try {
					Thread.sleep(1000); 
					zookeeper.create(path, "".getBytes(), 
							Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
				} catch (Exception e2) {
					count++;
					System.out.println("the " + count + " times try to acquire lock for product[id=" + productId + "]......");
					continue;
				}
				System.out.println("success to acquire lock for product[id=" + productId + "] after " + count + " times try......");
				break;
			}
		}
	}
	
	/**
	 * 獲取分佈式鎖
	 * @param productId
	 */
	public void acquireDistributedLock(String path) {
		try {
			zookeeper.create(path, "".getBytes(), 
					Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
			System.out.println("success to acquire lock for " + path);  
		} catch (Exception e) {
			// 如果那個商品對應的鎖的node,已經存在了,就是已經被別人加鎖了,那麼就這裏就會報錯
			// NodeExistsException
			int count = 0;
			while(true) {
				try {
					Thread.sleep(1000); 
					zookeeper.create(path, "".getBytes(), 
							Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
				} catch (Exception e2) {
					count++;
					System.out.println("the " + count + " times try to acquire lock for " + path + "......");
					continue;
				}
				System.out.println("success to acquire lock for " + path + " after " + count + " times try......");
				break;
			}
		}
	}
	
	/**
	 * 獲取分佈式鎖
	 * @param productId
	 */
	public boolean acquireFastFailedDistributedLock(String path) {
		try {
			zookeeper.create(path, "".getBytes(), 
					Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
			System.out.println("success to acquire lock for " + path);  
			return true;
		} catch (Exception e) {
			System.out.println("fail to acquire lock for " + path);  
		}
		return false;
	}
	
	/**
	 * 釋放掉一個分佈式鎖
	 * @param productId
	 */
	public void releaseDistributedLock(Long productId) {
		String path = "/product-lock-" + productId;
		try {
			zookeeper.delete(path, -1); 
			System.out.println("release the lock for product[id=" + productId + "]......");  
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 釋放掉一個分佈式鎖
	 * @param productId
	 */
	public void releaseDistributedLock(String path) {
		try {
			zookeeper.delete(path, -1); 
			System.out.println("release the lock for " + path + "......");  
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public String getNodeData(String path) {
		try {
			return new String(zookeeper.getData(path, false, new Stat())); 
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "";
	}
	
	public void setNodeData(String path, String data) {
		try {
			zookeeper.setData(path, data.getBytes(), -1);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void createNode(String path) {
		try {
			zookeeper.create(path, "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
		} catch (Exception e) {
			
		}
	}
	
	/**
	 * 建立zk session的watcher
	 * @author Administrator
	 *
	 */
	private class ZooKeeperWatcher implements Watcher {

		public void process(WatchedEvent event) {
			System.out.println("Receive watched event: " + event.getState());
			if(KeeperState.SyncConnected == event.getState()) {
				connectedSemaphore.countDown();
			} 
		}
		
	}
	
	/**
	 * 封裝單例的靜態內部類
	 * @author Administrator
	 *
	 */
	private static class Singleton {
		
		private static ZooKeeperSession instance;
		
		static {
			instance = new ZooKeeperSession();
		}
		
		public static ZooKeeperSession getInstance() {
			return instance;
		}
		
	}
	
	/**
	 * 獲取單例
	 * @return
	 */
	public static ZooKeeperSession getInstance() {
		return Singleton.getInstance();
	}
	
	/**
	 * 初始化單例的便捷方法
	 */
	public static void init() {
		getInstance();
	}
	
}

 

發佈了485 篇原創文章 · 獲贊 75 · 訪問量 83萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章