import java.util.concurrent.TimeUnit; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.framework.recipes.locks.InterProcessMutex; import org.apache.curator.retry.RetryNTimes; /** * ZooKeeper節點類型: <br> * ZooKeeper 節點是有生命周期的,這取決於節點的類型。<br> * 在 ZooKeeper 中,節點類型可以分為持久節點(PERSISTENT)、臨時節點(EPHEMERAL),以及時序節點(SEQUENTIAL)<br> * 具體在節點創建過程中,一般是組合使用,可以生成以下 4種節點類型<br> * * 持久節點(PERSISTENT) <br> * 所謂持久節點,是指在節點創建后,就一直存在,直到有刪除操作來主動清除這個節點。 <br> * (該節點不會因為創建該節點的客戶端會話失效而消失) * * 臨時節點(EPHEMERAL) <br> * 和持久節點不同的是,臨時節點的生命周期和客戶端會話綁定。<br> * 如果客戶端會話失效,那么這個節點就會自動被清除掉。<br> * (這里提到的是會話失效,而非連接斷開)<br> * 另外,在臨時節點下面不能創建子節點。<br> * * 持久順序節點(PERSISTENT_SEQUENTIAL) <br> * 這類節點的基本特性和上面的持久節點類型是一致的。<br> * 額外的特性是,在ZK中,每個父節點會為他的第一級子節點維護一份時序,會記錄每個子節點創建的先后順序。 <br> * 基於這個特性,在創建子節點的時候,可以設置這個屬性,那么在創建節點過程中,ZK會自動為給定節點名加上一個數字后綴,作為新的節點名。這個數字后綴的范圍是整型的最大值。<br> * 假如: 我們在/lock/目錄下創建節3個點,集群會按照提起創建的順序來創建節點,節點分別為/lock/0000000001、/lock/0000000002、/lock/0000000003。 * * 臨時順序節點(EPHEMERAL_SEQUENTIAL) <br> * 具有臨時節點和順序節點的特性。我們可以利用這個特性來實現分布式鎖。 <br> * 基於zookeeper瞬時有序節點實現的分布式鎖,其主要邏輯如下: <br> * 客戶端對某個功能加鎖時,在zookeeper上的與該功能對應的指定節點的目錄下,生成一個唯一的瞬時有序節點。 <br> * 判斷是否獲取鎖的方式,只需要判斷有序節點中序號最小的一個,如果最小的節點與當客戶端記錄節點號相同獲得鎖<br> * 當釋放鎖的時候,只需將這個瞬時節點刪除即可。 <br> * * Curator是Netflix公司開源的一個Zookeeper客戶端,提供了一些操作Zookeeper的方法,其中包括創建分布式鎖 <br>
*
* @author _yyl */ public class CuratorDistributedLockTest { private static final String ZK_ADDRESS = "localhost:2181"; private static final String ZK_LOCK_PATH = "/zktest/lock0"; /** * 下面的程序會啟動幾個線程去爭奪鎖,拿到鎖的線程會占用5秒 */ public static void main(String[] args) throws InterruptedException { // 1.Connect to zk CuratorFramework client = CuratorFrameworkFactory.newClient(ZK_ADDRESS, new RetryNTimes(10, 5000)); client.start(); System.out.println(client.getState()); System.out.println("zk client start successfully!"); InterProcessMutex lock = new InterProcessMutex(client, ZK_LOCK_PATH); for (int i = 0; i < 3; i++) { new Thread(() -> { doWithLock(client, lock); }, "Thread-" + i).start(); } } private static void doWithLock(CuratorFramework client, InterProcessMutex lock) { try { String name = Thread.currentThread().getName(); if (lock.acquire(10 * 1000, TimeUnit.SECONDS)) { System.out.println(name + " hold lock"); System.out.println(client.getChildren().forPath(ZK_LOCK_PATH)); Thread.sleep(5000L); System.out.println(name + " release lock"); } } catch (Exception e) { e.printStackTrace(); } finally { try { lock.release(); } catch (Exception e) { e.printStackTrace(); } } } }