可重入鎖ReentrantLock實(shí)現(xiàn)層面依賴(lài)
一谍肤、CAS(compareAndSet)
LockSupport
基本的方法
park
park使得當(dāng)前線(xiàn)程放棄cpu?進(jìn)入等待(waiting)狀態(tài)?操作系統(tǒng)不會(huì)再對(duì)其進(jìn)行調(diào)度
直到其他線(xiàn)程對(duì)它調(diào)用了unpark方法,其中unpark方法使得參數(shù)指定的線(xiàn)程恢復(fù)可運(yùn)行狀態(tài)
[1] part和Thread.yield()區(qū)別
-
yield 只是告訴操作系統(tǒng)可以讓其他線(xiàn)程先運(yùn)行亥鬓,但是自己可以仍是運(yùn)行態(tài)
-
park 方法則是放棄線(xiàn)程的運(yùn)行資格,使得線(xiàn)程進(jìn)入 WAITING 等待狀態(tài)
[2] 響應(yīng)中斷
park?方法是響應(yīng)中斷的耳峦,當(dāng)有中斷發(fā)生時(shí)驶鹉,park方法會(huì)返回轰驳,并且重新設(shè)置線(xiàn)程的中斷狀態(tài)
[3]2個(gè)變體
-
parkNanos:可以指定等待的最長(zhǎng)時(shí)間,參數(shù)是相對(duì)于當(dāng)前時(shí)間的納秒數(shù)
-
parkUntil:可以指定最長(zhǎng)等待的時(shí)間礁苗,參數(shù)是絕對(duì)時(shí)間爬凑,相對(duì)于紀(jì)元時(shí)的毫秒數(shù)
當(dāng)?shù)却瑫r(shí),方法就會(huì)返回试伙。同時(shí)還有一些其他的變體嘁信,可以指定一個(gè)對(duì)象于样,表示是由于該對(duì)象而進(jìn)行等待,以便于調(diào)試潘靖,一般情況下傳遞的參數(shù)為 this
getBlocker
二穿剖、AQS
- 提供了一個(gè)state字段 被volatile修飾 保證內(nèi)存可見(jiàn)性、順序性
- AQS內(nèi)部維護(hù)了一個(gè)等待隊(duì)列秘豹,借助CAS方法實(shí)現(xiàn)無(wú)阻塞算法進(jìn)行更新
三携御、ReentrantLock
Sync是抽象類(lèi)
NonfairSync是?fair?為?false?時(shí)使用的類(lèi)[默認(rèn)]
FairSync?是?fair?為?true?時(shí)需要使用的類(lèi)
lock實(shí)現(xiàn)
該方法被子類(lèi)重寫(xiě)
如果沒(méi)有被鎖定,則使用CAS進(jìn)行鎖定既绕;如果當(dāng)前線(xiàn)程已經(jīng)被鎖定啄刹,則增加鎖定次數(shù)。
如果?tryArquire方法返回false凄贩,則acquire方法會(huì)繼續(xù)調(diào)用acquireQueued(addWaiter(Node.EXCLUSIVE), arg)誓军。
其中,addWaiter 會(huì)新建一個(gè)節(jié)點(diǎn) Node疲扎,代表當(dāng)前線(xiàn)程昵时,然后加入內(nèi)部的等待隊(duì)列中。
在當(dāng)如等待隊(duì)列之后椒丧,調(diào)用?acquireQueued?來(lái)嘗試獲取鎖壹甥,其代碼為
是一個(gè)死循環(huán),在每次循環(huán)中壶熏,首先檢查當(dāng)前節(jié)點(diǎn)是否為第一個(gè)等待的節(jié)點(diǎn)句柠,
如果是且能獲取到鎖,就將當(dāng)前節(jié)點(diǎn)從等待隊(duì)列中移除并且返回棒假,
否則通過(guò)parkAndCheckInterrupt方法最終調(diào)用?LockSupport.park而放棄CPU溯职,
進(jìn)入等待狀態(tài),在被喚醒之后檢查是否發(fā)生了中斷帽哑,記錄中斷標(biāo)志谜酒。并且返回中斷標(biāo)志
如果能獲得鎖則立即獲得,如若不能則加入等待隊(duì)列妻枕。被喚醒之后檢查自己是否為第一個(gè)等待的線(xiàn)程僻族,如果是且能獲得鎖則返回,否則繼續(xù)等待佳头。如果在該過(guò)程中發(fā)生了中斷鹰贵, lock 會(huì)記錄中斷標(biāo)志位,但是不會(huì)提前返回或者拋除異常
unlock實(shí)現(xiàn)
tryRelease?方法會(huì)修改線(xiàn)程狀態(tài)并且釋放鎖康嘉,?unparkSuccessor?方法會(huì)調(diào)用?LockSupport.unpark?將第一個(gè)等待的線(xiàn)程喚醒
公平鎖和非公平鎖
公平鎖比非公平鎖在源碼實(shí)現(xiàn)上就多了一個(gè)檢查:當(dāng)沒(méi)有其他等待時(shí)間更長(zhǎng)的線(xiàn)程時(shí)碉输,才能獲取到鎖
公平鎖模型
初始化時(shí), state=0亭珍,表示沒(méi)有線(xiàn)程過(guò)來(lái)?yè)屾i敷钾。這時(shí)候枝哄,A線(xiàn)程請(qǐng)求鎖,占了鎖阻荒,把state+1
線(xiàn)程A取得了鎖挠锥,把?state原子性+1,這時(shí)候state被改為1,A線(xiàn)程繼續(xù)執(zhí)行其他任務(wù)侨赡,然后線(xiàn)程B請(qǐng)求鎖蓖租,線(xiàn)程B無(wú)法獲取鎖,生成節(jié)點(diǎn)進(jìn)行排隊(duì)
初始化的時(shí)候羊壹,會(huì)生成一個(gè)空的頭節(jié)點(diǎn)蓖宦,然后才是B線(xiàn)程節(jié)點(diǎn),這時(shí)候油猫,如果線(xiàn)程A又請(qǐng)求鎖稠茂,是否需要排隊(duì)?答案當(dāng)然是否定的情妖,否則就直接死鎖了睬关。當(dāng)A再次請(qǐng)求鎖
可重入鎖:就是一個(gè)線(xiàn)程在獲取了鎖之后,再次去獲取了同一個(gè)鎖毡证,這時(shí)候僅僅是把狀態(tài)值進(jìn)行累加电爹。如果線(xiàn)程A釋放了一次鎖
僅僅是把狀態(tài)值減了,只有線(xiàn)程A把此鎖全部釋放了料睛,狀態(tài)值減到0了藐不,其他線(xiàn)程才有機(jī)會(huì)獲取鎖。當(dāng)A把鎖完全釋放后秦效,state恢復(fù)為0,然后會(huì)通知隊(duì)列喚醒B線(xiàn)程節(jié)點(diǎn)涎嚼,使B可以再次競(jìng)爭(zhēng)鎖阱州。當(dāng)然,如果B線(xiàn)程后面還有C線(xiàn)程法梯,C線(xiàn)程繼續(xù)休眠苔货,除非B執(zhí)行完了,通知了C線(xiàn)程立哑。注意夜惭,當(dāng)一個(gè)線(xiàn)程節(jié)點(diǎn)被喚醒然后取得了鎖,對(duì)應(yīng)節(jié)點(diǎn)會(huì)從隊(duì)列中刪除
非公平鎖模型
當(dāng)線(xiàn)程A執(zhí)行完之后铛绰,要喚醒線(xiàn)程B是需要時(shí)間的诈茧,而且線(xiàn)程B醒來(lái)后還要再次競(jìng)爭(zhēng)鎖,所以如果在切換過(guò)程當(dāng)中捂掰,來(lái)了一個(gè)線(xiàn)程C敢会,那么線(xiàn)程C是有可能獲取到鎖的曾沈,如果C獲取到了鎖,B就只能繼續(xù)休眠了
為什么不默認(rèn)是公平鎖
保證公平整體性能會(huì)比較低鸥昏,其原因不是因?yàn)闄z查慢塞俱,而是因?yàn)闀?huì)讓活躍線(xiàn)程無(wú)法得到鎖,從而進(jìn)入等待狀態(tài)吏垮,引起了頻繁的上下文切換障涯,降低了整體的效率
ReentrantLock tryLock()方法使用的是非公平鎖
和synchronized比較
-
ReentrantLock可以實(shí)現(xiàn)與 synchronized 相同的語(yǔ)義 而且支持以非阻塞方式獲取鎖,也可以想用中斷膳汪,限時(shí)阻塞唯蝶,更為靈活;synchronized 的使用更為簡(jiǎn)單,代碼量也更少
-
synchronized 代表的是一種聲明式編程思維 由 Java 系統(tǒng)負(fù)責(zé)實(shí)現(xiàn) 程序員并不清楚實(shí)現(xiàn)細(xì)節(jié);顯式鎖代表一種命令式編程思維旅敷,使用者需要實(shí)現(xiàn)所有的細(xì)節(jié)
-
聲明式編程的好處除了簡(jiǎn)單生棍,在性能上也有所體現(xiàn)。在較新版本的 JVM 上媳谁,ReentrantLock和synchronized的性能是接近的涂滴, 并且 Java 編譯器和虛擬機(jī)會(huì)不斷優(yōu)化 synchronized 的實(shí)現(xiàn),比如自動(dòng)分析 synchronized 的使用晴音,對(duì)于沒(méi)有鎖競(jìng)爭(zhēng)的場(chǎng)景柔纵,自動(dòng)忽略對(duì)獲取鎖/釋放鎖的調(diào)用
-
能用 synchronized 就用 synchronized,不滿(mǎn)足使用要求的時(shí)候考慮使用 ReentrantLock
代碼資源
https://gitee.com/pingfanrenbiji/myconcurrent/blob/master/src/main/java/pers/hanchao/concurrent/reentrantLock/LockSupportTest.java
參考文章
https://blog.csdn.net/u011669700/article/details/80070892
https://blog.csdn.net/yanyan19880509/article/details/52345422