ZooKeeper 分佈式鎖 Curator 源碼 03:可重入鎖併發加鎖

前言

在瞭解了加鎖和鎖重入以後,最須要了解的仍是在分佈式場景下或者多線程併發加鎖是如何處理的?多線程

併發加鎖

先來看結果,在多線程對 /locks/lock_01 加鎖時,是在後面又建立了新的臨時節點。併發

這塊在加鎖方法 CreateBuilderImpl#pathInForeground 中已經介紹過框架

這裏判斷 /locks/lock_01 路徑已經存在,會直接建立新的臨時順序節點。分佈式

真正判斷鎖是否獲取成功,實際上是在 LockInternals#attemptLock 方法中的 internalLockLoop 方法中。oop

加鎖結果及監聽

internalLockLoop 方法的主要做用是判斷加鎖結果,以及獲取鎖失敗時,對其餘節點的監聽。ui

  1. 獲取父節點 /locks/lock_01 下的全部子節點,按照從小到大排序,判斷本身是否是獲取到鎖,沒有獲取到就監聽本身前一個節點;
  2. 支持設置超時時間,超時直接返回失敗;
  3. 不支持設置超時時間或者尚未超時,則直接 wait 等待。

是否獲取鎖的代碼在 StandardLockInternalsDriver#getsTheLock線程

這塊就是判斷是否爲最小節點,由於在 getSortedChildren 中已經對全部節點排序,因此方法中的 List<String> children 是有序的。code

maxLeases 是在 InterProcessMutex 初始化的時候,指定的值爲 1。blog

最終這裏的結果是,判斷本身是否是最小,不是最小,就將 pathToWatch 設置爲前一個節點排序

只監聽本身的前一個節點,能夠避免羊羣效應!

爲何要進行等待呢?

由於是爲了防止無效自旋,由於這裏有監聽機制,會監聽上一個節點是否釋放。

這塊是 ZooKeeper 的 Watcher 監聽機制,在節點釋放的時候,會進行回調,而後使用 Java 的 notifyAll 方法通知全部的 wait 線程。而後這裏的 while trye 會繼續執行,從新檢查是否得到鎖等。

總結

本文主要介紹了基於 ZooKeeper 的分佈式鎖框架 Curator 在併發場景下的鎖競爭問題。

重點須要瞭解的是:

  1. 爲了不羊羣效應,臨時順序節點,加鎖失敗後監聽的是前一個節點
  2. 爲了不無效自旋,這裏使用了 Java 的 wait/notifyAll 機制;
  3. 能夠看出,默認加鎖就是公平鎖

相關推薦

相關文章
相關標籤/搜索