日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
從Java鎖到分布式鎖

從 Java 鎖到分布式鎖

作者:程序員小航 2021-11-26 06:43:19

開發(fā)

后端

分布式 在并發(fā)編程中常用到 synchronized 以及 ReentrantLock 鎖,在業(yè)務(wù)開發(fā)過程中也可能會(huì)用到分布式鎖,分布式鎖常用框架的就是基于 Redis 實(shí)現(xiàn)的分布式鎖框架 Redisson 和 基于 Zookeeper 實(shí)現(xiàn)的分布式鎖框架 Curator。當(dāng)然,也有其他的鎖實(shí)現(xiàn)方式,在這里不做介紹。

成都創(chuàng)新互聯(lián)在網(wǎng)站設(shè)計(jì)、網(wǎng)站制作、手機(jī)APP定制開發(fā)、網(wǎng)站運(yùn)營(yíng)等方面均有出色的表現(xiàn),憑借多年豐富的經(jīng)驗(yàn),我們會(huì)仔細(xì)了解各客戶的需求而做出多方面的分析、設(shè)計(jì)、整合,為客戶設(shè)計(jì)出具風(fēng)格及創(chuàng)意性的商業(yè)解決方案,我們更提供一系列網(wǎng)絡(luò)營(yíng)銷推廣,網(wǎng)站制作和網(wǎng)站推廣的服務(wù),以推動(dòng)各中小企業(yè)全面信息化,并利用創(chuàng)新技術(shù)幫助各行業(yè)提升企業(yè)形象和運(yùn)營(yíng)效率。

前言

在并發(fā)編程中常用到 synchronized 以及 ReentrantLock 鎖,在業(yè)務(wù)開發(fā)過程中也可能會(huì)用到分布式鎖,分布式鎖常用框架的就是基于 Redis 實(shí)現(xiàn)的分布式鎖框架 Redisson 和 基于 Zookeeper 實(shí)現(xiàn)的分布式鎖框架 Curator。當(dāng)然,也有其他的鎖實(shí)現(xiàn)方式,在這里不做介紹。

本文主要是在學(xué)習(xí) Java 鎖以及分布式鎖的源碼后,做出的歸納總結(jié)。

1鎖的最基本要素

為什么要使用鎖?

關(guān)于為什么要使用鎖這個(gè)問題,答案顯而易見:“為了避免多線程并發(fā)沖突”。

在多線程中對(duì)公共數(shù)據(jù)的修改,必須要保證只有線程在進(jìn)行操作。這里的公共數(shù)據(jù)可以是公共變量,也可以是數(shù)據(jù)庫中的一行數(shù)據(jù)。

鎖的基本要素

知道為什么要加鎖之后,就可以得出加鎖的基本要素:

  • 鎖標(biāo)志:怎么樣才算加鎖成功?
  • 鎖持有者:是哪個(gè)線程加的鎖?
  • 鎖重入:自己加了鎖之后,再次加鎖?
  • 鎖并發(fā):并發(fā)加鎖失敗的線程該怎么辦?
  • 鎖釋放:用完鎖,該怎么釋放?

簡(jiǎn)單來說應(yīng)該就是這些要素,遺漏之處,歡迎補(bǔ)充。

2加鎖標(biāo)志

加鎖標(biāo)志,就是需要一個(gè)標(biāo)志來表示是否加鎖成功,并且這個(gè)加鎖標(biāo)志要保證原子性。

  • synchronized 底層是 C++ 實(shí)現(xiàn)的,在 ObjectMonitor 對(duì)象中有一個(gè) _count 參數(shù)用來標(biāo)識(shí)是否持有鎖。
  • ReentrantLock 基于 AQS 實(shí)現(xiàn),其中 state 表示線程是否持有鎖。ReentrantReadWriteLock 同樣基于 AQS 實(shí)現(xiàn),其中 state 高 16 位表示讀鎖,低 16 位表示寫鎖。
  • Redisson 是基于 Redis 的 Hash 數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)的,其中加鎖 key 是否存在,可以表示是否加鎖。
  • Curator 基于 ZooKeeper 臨時(shí)順序節(jié)點(diǎn)實(shí)現(xiàn),判斷加鎖路徑下是否存在該節(jié)點(diǎn),來表示是否加鎖。

3鎖持有者

  • 鎖持有者,肯定是當(dāng)前線程,但是在分布式鎖中還需要加上機(jī)器,用來防止服務(wù)之間的線程沖突。
  • synchronized 在 ObjectMonitor 對(duì)象中 _owner 是指獲得鎖的線程。
  • ReentrantLock 和 ReentrantReadWriteLock 是在 AQS 的 Node 節(jié)點(diǎn)中有 Thread 對(duì)象,用來表示獲得鎖的線程。
  • Redisson 在 Hash 數(shù)據(jù)結(jié)構(gòu)的 field 字段存放的是 UUID:ThreadId,從而保證在多個(gè)服務(wù)實(shí)例時(shí)防止并發(fā)沖突。
  • Curator 創(chuàng)建的臨時(shí)順序節(jié)點(diǎn)包含 UUID,表示加鎖機(jī)器,結(jié)構(gòu)比如 /locks/lock_01/_c_UUID-lock-0000000000。

4鎖重入

當(dāng)獲得鎖的線程再次嘗試獲取鎖的時(shí)候,保證需要計(jì)數(shù)。

  • synchronized 會(huì)對(duì) _count 進(jìn)行累加,CAS 更新。
  • ReentrantLock 會(huì)對(duì) AQS 的 state 進(jìn)行累加,CAS 更新。
  • Redisson 使用 Lua 腳本,對(duì) Hash 結(jié)構(gòu)的 value 進(jìn)行累加。
  • Curator 是在 Java 代碼中維護(hù)了一個(gè) AtomicInteger 類型的 lockCount 字段,用來表示重入。

5鎖等待

  • synchronized 并發(fā)加鎖失敗線程會(huì)自旋等待,涉及到偏向鎖、輕量級(jí)鎖、重量級(jí)鎖的鎖升級(jí)流程。
  1. 剛開始是無鎖的
  2. 偏向鎖:一段同步代碼一直被一個(gè)線程訪問,這個(gè)線程自動(dòng)獲取鎖,大多數(shù)都是由同一個(gè)線程獲取鎖,這就會(huì)出現(xiàn)偏向鎖。目的是只有一個(gè)線程執(zhí)行同步代碼塊時(shí)提高性能,JDK 6 后在 JVM 中默認(rèn)開啟。對(duì)象頭標(biāo)志位(01-無鎖) 是否偏向鎖標(biāo)志(1-是偏向鎖)
  3. 輕量級(jí)鎖:鎖是偏向鎖時(shí),被其他線程訪問,偏向鎖就升級(jí)為輕量級(jí)鎖,其他線程通過自旋形式嘗試獲取鎖 對(duì)象頭標(biāo)志位 00
  4. 重量級(jí)鎖:只有一個(gè)線程等待,該線程是在自旋等待獲取鎖。當(dāng)自旋一定次數(shù)或者一個(gè)持有鎖一個(gè)自旋時(shí)來了第三個(gè)線程,就會(huì)升級(jí)為重量級(jí)鎖。對(duì)象頭標(biāo)志位 10
  • ReentrantLock 會(huì)放到 AQS 雙向同步隊(duì)列中,監(jiān)聽上一個(gè)節(jié)點(diǎn)是否為虛擬頭結(jié)點(diǎn),是則嘗試獲取鎖。
    • 非公平鎖新線程會(huì)默認(rèn)參加搶鎖,公平鎖會(huì)先查看隊(duì)列是否為空。
    • 自旋等待時(shí)會(huì)使用 LockSupport.park() 方法,這時(shí)候會(huì)讓出 CPU 資源,其他線程會(huì)調(diào)用 LockSupport.unpark()。
    • 可以使用 tryLock 方法設(shè)置時(shí)間,在指定時(shí)間內(nèi)獲取鎖失敗或者被中斷,則會(huì)返回加鎖失敗。
  • Redisson 并發(fā)加鎖,失敗線程會(huì)獲取到當(dāng)前鎖的超時(shí)時(shí)間,然后通過 Semaphore tryAcquire 方法阻塞一定時(shí)間后,再次嘗試獲取鎖。
    • 公平鎖會(huì)額外使用 Redis 的 List 數(shù)據(jù)結(jié)構(gòu)來當(dāng)做線程等待隊(duì)列,使用 sorted set 有序集合數(shù)據(jù)結(jié)構(gòu)來存放等待線程的順序(score 是超時(shí)時(shí)間戳)。
  • Curator 并發(fā)加鎖會(huì)直接創(chuàng)建臨時(shí)順序節(jié)點(diǎn),然后監(jiān)聽順序節(jié)點(diǎn)中自己的上一個(gè)節(jié)點(diǎn)(防止羊群效應(yīng)),默認(rèn)是公平鎖。

6鎖釋放

  • synchronized 不需要手動(dòng)釋放。
  • ReentrantLock 對(duì) state 遞減為 0 后,喚醒后續(xù)節(jié)點(diǎn),有后續(xù)節(jié)點(diǎn)需要調(diào)用 LockSupport.unpark(s.thread)。
  • Redisson 主動(dòng)釋放直接刪除 key 即可。超時(shí)釋放即服務(wù)宕機(jī),沒有看門狗續(xù)租了,指定時(shí)間后,Redis Key 就會(huì)被自動(dòng)釋放。
  • Curator 主動(dòng)釋放會(huì)刪除節(jié)點(diǎn),如果服務(wù)宕機(jī)了,節(jié)點(diǎn)會(huì)被自動(dòng)刪除。

7總結(jié)

本文從多個(gè)角度總結(jié)分析了鎖和分布式鎖的基本要素,同樣基于 MySQL 等數(shù)據(jù)庫的鎖可以參考實(shí)現(xiàn)。

 本文轉(zhuǎn)載自微信公眾號(hào)「程序員小航」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系程序員小航公眾號(hào)。


分享標(biāo)題:從Java鎖到分布式鎖
網(wǎng)站地址:http://www.5511xx.com/article/coscegp.html