1. 程式人生 > 其它 >Java基礎回顧:各種鎖

Java基礎回顧:各種鎖

參考:

https://tech.meituan.com/2018/11/15/java-lock.html

型別

1. 樂觀鎖 & 悲觀鎖 樂觀鎖與悲觀鎖是一種廣義上的概念。
  • 悲觀鎖:對於同一個資料,悲觀鎖認為執行緒在使用資料時,總有其他執行緒來修改資料,因此在獲取資料的時候回先加鎖,確保資料不會被其他執行緒修改。java中Synchronized關鍵字和Lock介面實現類都是悲觀鎖。如下:
  • 樂觀鎖:樂觀鎖認為自己在使用資料時不會有其他執行緒來修改資料,所以不會新增鎖。指示在更新資料的時候去判斷資料是否有被其他執行緒更新。如果這個資料沒被更新,則當前執行緒獲取資料並更新,如果資料已經被其他執行緒修改,則根據不同的實現方式執行不同的操作(例如報錯或自動重試)。樂觀鎖在Java中是通過無鎖程式設計來實現,最常採用的CAS演算法,Java原子類中的遞增操作就通過CAS自旋實現的。
  •   CAS:一種無鎖演算法,Compare And Swap(比較交換)。
    • 需要讀寫的記憶體位置V
    • 需要進行比較的預期值A
    • 需要寫入的新值U
    CAS 存在問題:       ABA問題(加版本號解決),迴圈時間長開銷大,只能保證一個共享變數 的原子操作。 悲觀鎖是和寫操作多的場景,先加鎖可以保證資料正確性; 樂觀鎖適合讀操作多的場景,不加鎖的特性可以使讀操作的效能大大提升。 2. 自旋鎖 & 適應性自旋鎖 自旋鎖實現原理:CAS 例:AtomicInteger自增操作 適應性自旋鎖:自旋的次數不再固定,由前一次在同一個鎖上的自旋時間及鎖的擁有者狀態來決定。 3. 無鎖 & 偏向鎖 & 輕量級鎖 & 重量級鎖
無鎖:沒有對資源進行鎖定,所有執行緒都能訪問並修改同一個資源,但同時只有一個執行緒能修改成功,實現:CAS 偏向鎖:指一段同步程式碼一直被同一個執行緒訪問,那麼該執行緒會自動獲取鎖,降低獲取鎖的代價。偏向鎖只有遇到其他執行緒嘗試競爭偏向鎖時,持有偏向鎖的執行緒才會釋放鎖,執行緒不會主動釋放偏向鎖。 jdk6以後預設開啟 JVM引數 -XX:-UseBiasedLocking=false 輕量級鎖:當鎖是偏向鎖時,被其他執行緒訪問,偏向鎖就會升級為輕量級鎖,其他執行緒會通過自旋的方式獲取鎖,不會阻塞,從而提高效能。CAS+自旋 重量級鎖:若當前只有一個等待執行緒,則該執行緒通過自旋進行等待。但是當自旋超過一定的次數,或者一個執行緒在持有鎖,一個在自旋,又有第三個來訪時,輕量級鎖升級為重量級鎖。 4. 公平鎖 & 非公平鎖
公平鎖:多個執行緒按照申請鎖的順序來獲取鎖,執行緒在佇列中排隊,佇列中第一個執行緒獲取鎖。執行緒不會餓死,但是效率低。 非公平鎖:執行緒直接嘗試去獲取鎖,獲取不到才進入佇列等待。效率高,但是執行緒有可能餓死。 例:ReentrantLock有一個內部類Sync,Sync繼承AQS(AbstractQueuedSybchronizer),加鎖和釋放鎖多事類Sync實現,有公平鎖(FairSync extends Sync)和非公平鎖(NonfairSync extends Sync),預設使用非公平鎖。 5. 可重入鎖 & 非可重入鎖 可重入鎖:同一個執行緒可以重複獲取鎖,獲取一次鎖status加1,釋放一次鎖status減1,可重入鎖的一個優點是可一定程度避免死鎖。ReentrantLock和Synchronized都是可重入鎖。 非可重入鎖:NonReentrantLock 6. 獨享鎖 & 共享鎖 獨享鎖:排它鎖,該鎖只能被一個執行緒持有。 共享鎖:可以被多個執行緒持有。 一點浩然氣,千里快哉風!