分布式的鎖全局同步, 這意味着任何一個時間點不會有兩個用戶端都擁有相同的鎖。
首先我們先看一個全局可重入的鎖。 shared意味着鎖是全局可見的, 用戶端都可以請求鎖。 reentrant和jdk的reentrantlock類似, 意味着同一個用戶端在擁有鎖的同時,可以多次擷取,不會被阻塞。 它是由類<code>interprocessmutex</code>來實作。 它的構造函數為:
通過<code>acquire</code>獲得鎖,并提供逾時機制:
通過<code>release()</code>方法釋放鎖。 interprocessmutex 執行個體可以重用。
revoking zookeeper recipes wiki定義了可協商的撤銷機制。 為了撤銷mutex, 調用下面的方法:
如果你請求撤銷目前的鎖, 調用<code>revoker</code>方法。
錯誤處理 還是強烈推薦你使用<code>connectionstatelistener</code>處理連接配接狀态的改變。 當連接配接lost時你不再擁有鎖。
首先讓我們建立一個模拟的共享資源, 這個資源期望隻能單線程的通路,否則會有并發問題。
然後建立一個<code>exampleclientthatlocks</code>類, 它負責請求鎖, 使用資源,釋放鎖這樣一個完整的通路過程。
最後建立主程式來測試。
代碼也很簡單,生成10個client, 每個client重複執行10次 請求鎖–通路資源–釋放鎖的過程。每個client都在獨立的線程中。 結果可以看到,鎖是随機的被每個執行個體排他性的使用。
既然是可重用的,你可以在一個線程中多次調用<code>acquire</code>,線上程擁有鎖時它總是傳回true。
你不應該在多個線程中用同一個interprocessmutex, 你可以在每個線程中都生成一個interprocessmutex執行個體,它們的path都一樣,這樣它們可以共享同一個鎖。
這個鎖和上面的相比,就是少了<code>reentrant</code>的功能,也就意味着它不能在同一個線程中重入。 這個類是<code>interprocesssemaphoremutex</code>。 使用方法和上面的類類似。
首先我們将上面的例子修改一下,測試一下它的重入。 修改<code>exampleclientthatlocks.dowork</code>,連續兩次<code>acquire</code>:
注意我們也需要調用<code>release</code>兩次。這和jdk的reentrantlock用法一緻。如果少調用一次<code>release</code>,則此線程依然擁有鎖。 上面的代碼沒有問題,我們可以多次調用<code>acquire</code>,後續的<code>acquire</code>也不會阻塞。 将上面的<code>interprocessmutex</code>換成不可重入鎖<code>interprocesssemaphoremutex</code>,如果再運作上面的代碼,結果就會發現線程被阻塞再第二個<code>acquire</code>上。 也就是此鎖不是可重入的。
類似jdk的<code>reentrantreadwritelock</code>. 一個讀寫鎖管理一對相關的鎖。 一個負責讀操作,另外一個負責寫操作。 讀操作在寫鎖沒被使用時可同時由多個程序使用,而寫鎖使用時不允許讀 (阻塞)。 此鎖是可重入的。一個擁有寫鎖的線程可重入讀鎖,但是讀鎖卻不能進入寫鎖。 這也意味着寫鎖可以降級成讀鎖, 比如請求寫鎖 —>讀鎖 —->釋放寫鎖。 從讀鎖更新成寫鎖是不成的。
主要由兩個類實作:
interprocessreadwritelock
interprocesslock
使用時首先建立一個<code>interprocessreadwritelock</code>執行個體,然後再根據你的需求得到讀鎖或者寫鎖, 讀寫鎖的類型是<code>interprocesslock</code>。
例子和上面的類似。
在這個類中我們首先請求了一個寫鎖, 然後降級成讀鎖。 執行業務處理,然後釋放讀寫鎖。
一個計數的信号量類似jdk的semaphore。 jdk中semaphore維護的一組許可(permits),而cubator中稱之為租約(lease)。 有兩種方式可以決定semaphore的最大租約數。第一種方式是有使用者給定的path決定。第二種方式使用<code>sharedcountreader</code>類。 如果不使用sharedcountreader, 沒有内部代碼檢查程序是否假定有10個租約而程序b假定有20個租約。 是以所有的執行個體必須使用相同的numberofleases值.
這次調用<code>acquire</code>會傳回一個租約對象。 用戶端必須在finally中close這些租約對象,否則這些租約會丢失掉。 但是, 但是,如果用戶端session由于某種原因比如crash丢掉, 那麼這些用戶端持有的租約會自動close, 這樣其它用戶端可以繼續使用這些租約。 租約還可以通過下面的方式返還:
注意一次你可以請求多個租約,如果semaphore目前的租約不夠,則請求線程會被阻塞。 同時還提供了逾時的重載方法。
主要類有:
interprocesssemaphorev2
lease
sharedcountreader
下面是使用的例子:
首先我們先獲得了5個租約, 最後我們把它還給了semaphore。 接着請求了一個租約,因為semaphore還有5個租約,是以請求可以滿足,傳回一個租約,還剩4個租約。 然後再請求一個租約,因為租約不夠,阻塞到逾時,還是沒能滿足,傳回結果為null。
上面說講的鎖都是公平鎖(fair)。 總zookeeper的角度看, 每個用戶端都按照請求的順序獲得鎖。 相當公平。
multi shared lock是一個鎖的容器。 當調用<code>acquire</code>, 所有的鎖都會被<code>acquire</code>,如果請求失敗,所有的鎖都會被release。 同樣調用release時所有的鎖都被release(失敗被忽略)。 基本上,它就是組鎖的代表,在它上面的請求釋放操作都會傳遞給它包含的所有的鎖。
主要涉及兩個類:
interprocessmultilock
它的構造函數需要包含的鎖的集合,或者一組zookeeper的path。
用法和shared lock相同。
例子如下:
建立一個interprocessmultilock, 包含一個重入鎖和一個非重入鎖。 調用<code>acquire</code>後可以看到線程同時擁有了這兩個鎖。 調用<code>release</code>看到這兩個鎖都被釋放了。
再重申以便, 強烈推薦使用connectionstatelistener監控連接配接的狀态。