JUC之Locks鎖面經(jīng)整理

照例浓恶,首先看看JUC中Locks的結(jié)構(gòu)

ocks的結(jié)構(gòu)

看著很短固以,但是有關(guān)鎖的內(nèi)容卻很長(zhǎng)掂僵,需要時(shí)間消化


大致我們可以從以下幾個(gè)方面來(lái)講解

目錄1
目錄2

鎖是JUC中至關(guān)重要的內(nèi)容稿辙,日常開發(fā)中也用的很多昆码,對(duì)于并發(fā)而言更是至關(guān)重要,因此在面試中被問起的概率非常高邻储,所以對(duì)于這一塊的內(nèi)容要著重掌握


一赋咽、locks的概念

java提供各類鎖的一個(gè)框架。


二吨娜、locks分類

(一)按鎖的性質(zhì)劃分

1脓匿、按多個(gè)線程是否按順序獲取鎖的角度劃分

a、公平鎖

當(dāng)鎖被某個(gè)線程持有時(shí)宦赠,新發(fā)出請(qǐng)求的線程會(huì)被放入隊(duì)列中陪毡,在公平鎖中,每一次嘗試獲取鎖都會(huì)檢查CLH隊(duì)列中是否仍有前驅(qū)的元素勾扭,如果仍然有那么繼續(xù)等待毡琉。

獲取方法:公平鎖在獲取鎖之前會(huì)先判斷等待隊(duì)列是否為空或者自己位于隊(duì)列首部,如果為true則可以繼續(xù)獲取鎖妙色,否則就入隊(duì)等待桅滋。

缺點(diǎn):公平鎖為了保證線程排隊(duì),需要增加阻塞和喚醒的時(shí)間開銷

源碼分析:

公平鎖源碼分析

深入看看hasQueuePredecessors()身辨,作用是判斷此線程是否應(yīng)該放入等待隊(duì)列丐谋。首先說明一下這個(gè)等待隊(duì)列是個(gè)頭結(jié)點(diǎn)不存在元素的隊(duì)列。h != t && ((s = h.next) == null || s.thread != Thread.currentThread());表示此隊(duì)列不為空并且這個(gè)線程不在頭結(jié)點(diǎn)處煌珊。

b笋鄙、非公平鎖

非公平鎖和公平鎖在獲取鎖的方法上,流程是一樣的怪瓶;它們的區(qū)別主要表現(xiàn)在“嘗試獲取鎖的機(jī)制不同”

獲取方法:無(wú)視等待隊(duì)列直接嘗試獲取鎖萧落,如果鎖是空閑的践美,即可獲取狀態(tài),則獲取鎖

優(yōu)點(diǎn):可以減少喚起線程的開銷

缺點(diǎn):處于等待隊(duì)列中的線程可能會(huì)出現(xiàn)一直獲取不到鎖的現(xiàn)象(餓死)

饑餓原因:

1.高優(yōu)先級(jí)線程占用所有CPU找岖,低優(yōu)先級(jí)進(jìn)程一直無(wú)法獲取

2.一個(gè)線程每次競(jìng)爭(zhēng)鎖都失敗陨倡,而新的線程還在一直不斷競(jìng)爭(zhēng),從而導(dǎo)致這個(gè)線程幾乎是一直處于等待中

3.某個(gè)線程在某個(gè)對(duì)象的條件隊(duì)列上等待许布,而其他線程不斷搶入

final void lock() {

????if (compareAndSetState(0, 1))

????????setExclusiveOwnerThread(Thread.currentThread());

????else

????????acquire(1);

}

可以看到獲取鎖的時(shí)候是直接去獲取的兴革,compareAndSetState(0,1)修改鎖的狀態(tài),修改成功則表示鎖已經(jīng)被釋放了蜜唾,然后把占有鎖的線程改為本線程杂曲。

PS:ReentrantLock、ReadWriteLock袁余、Synchronized默認(rèn)都是非公平模式

c.使用場(chǎng)景

公平鎖:線程處理時(shí)間過長(zhǎng)擎勘,一部分客戶端獲取不到服務(wù)(違反公平原則,一直被新的線程占用CPU)

非公平鎖:當(dāng)線程吞吐量大的時(shí)候


2颖榜、按多個(gè)線程是否可以持有同一把鎖的角度劃分

a.獨(dú)享鎖(互斥鎖/寫鎖):

是指該鎖一次只能被一個(gè)線程鎖持有

ReentrantLock和Synchronized都是獨(dú)占鎖棚饵。

ReentrantReadWriteLock為讀寫鎖,對(duì)于讀操作是共享鎖掩完,對(duì)于寫操作是獨(dú)占鎖噪漾。這樣可以做到讀讀操作不互斥,但是讀寫且蓬、寫讀和寫寫操作都是互斥的欣硼。

PS:CopyOnWriteArrayList,對(duì)它的操作可以做到寫寫互斥、其他三個(gè)操作不互斥恶阴。

b.共享鎖(讀鎖)

是指該鎖可被多個(gè)線程所持有


3分别、按一個(gè)線程能否重復(fù)獲取自己的所得角度劃分

a.重入鎖(遞歸鎖)

同一個(gè)線程而言,它可以重復(fù)的獲取鎖存淫,避免同一個(gè)線程重復(fù)獲取鎖發(fā)生死鎖。

外層方法獲得鎖之后沼填,進(jìn)入內(nèi)層方法調(diào)用的方法自動(dòng)獲得桅咆,并不會(huì)阻塞。(同一個(gè)線程坞笙,可以多次獲得同一把可重入鎖)

ReentrantLock就是重入鎖岩饼,如下:

ReentrantLock重入鎖舉例 ?

可以看到,在print()方法的同步塊中薛夜,調(diào)用dosomething()方法時(shí)又獲得了這把鎖籍茧,這個(gè)時(shí)候這把鎖還沒有釋放,也就是上一節(jié)中的代碼中的state并不為0梯澜,但由于是可充入鎖寞冯,所以并不會(huì)阻塞,而是將acquires變量+1。注意可重入鎖的可重入性只針對(duì)本線程吮龄。

b.不重入鎖

一個(gè)線程多次請(qǐng)求同一把鎖俭茧,會(huì)出現(xiàn)死鎖

優(yōu)點(diǎn):效率更高

缺點(diǎn):易發(fā)生死鎖


(二)按鎖的設(shè)計(jì)方案來(lái)分類

1、按多個(gè)線程競(jìng)爭(zhēng)同一把鎖是否進(jìn)行阻塞劃分

a.自旋鎖

當(dāng)有另外一個(gè)線程來(lái)競(jìng)爭(zhēng)鎖時(shí)漓帚,這個(gè)線程會(huì)在原地等待母债,而不是把該線程給阻塞,直到那個(gè)獲得鎖的線程釋放之后尝抖,這個(gè)線程馬上獲得鎖

自旋鎖的應(yīng)用就是CAS操作 +?循環(huán)

自旋鎖

b.自適應(yīng)自旋鎖

自旋的時(shí)間(次數(shù))不再固定毡们,而是由前一次在同一個(gè)鎖上的自選時(shí)間及鎖的擁有者狀態(tài)來(lái)決定:

1.如果同一個(gè)鎖對(duì)象上,自旋等待剛剛成功獲得過鎖昧辽,并且持有鎖的線程正在運(yùn)行中衙熔,那么虛擬機(jī)就會(huì)認(rèn)為這次自旋也很有可能再次成功,進(jìn)而它將允許自旋等待持續(xù)相對(duì)更長(zhǎng)的時(shí)間奴迅;

2.如果對(duì)于某個(gè)鎖青责,自旋很少成功獲得過,那在以后嘗試獲取這個(gè)鎖時(shí)將可能省略掉自旋過程取具,直接阻塞進(jìn)程脖隶,避免浪費(fèi)處理器資源。

c.優(yōu)缺點(diǎn)分析

自旋鎖是一種非阻塞鎖暇检,如果某線程需要獲取自旋鎖产阱,但該鎖已經(jīng)被其他線程占用時(shí),該線程不會(huì)被掛起块仆,而是在不斷的消耗CPU的時(shí)間构蹬,不停的試圖獲取自旋鎖,自旋鎖不會(huì)使線程狀態(tài)發(fā)生切換執(zhí)行速度快悔据,但是會(huì)不斷消耗CPU庄敛。


2、按多個(gè)線程并發(fā)時(shí)鎖的力度以及鎖競(jìng)爭(zhēng)劃分

a.分段鎖

在鎖發(fā)生競(jìng)爭(zhēng)時(shí)使用獨(dú)享鎖保護(hù)受限資源科汗,一次只能有一個(gè)線程能訪問獨(dú)享鎖藻烤,但是這樣的話效率很低,因此可以采用一種機(jī)制來(lái)協(xié)調(diào)獨(dú)享鎖進(jìn)而提高并發(fā)性头滔,這個(gè)機(jī)制就是分段鎖怖亭。

案例:ConcurrentHashMap(JDK1.7)支持多達(dá)16個(gè)并發(fā)的寫入操作

ConcurrentHashMap(JDK1.7)

如圖所示,ConcurrentHashMap默認(rèn)分成了16個(gè)segment坤检,每個(gè)segment都對(duì)應(yīng)一個(gè)Hash表兴猩,且都由獨(dú)立的鎖(ReetrantLock)。所以這樣就每個(gè)線程訪問一個(gè)Segment早歇,就可以并行訪問了倾芝,從而提高了效率讨勤,這就是鎖分段。

缺點(diǎn):與單個(gè)鎖相比蛀醉,獲取多個(gè)鎖來(lái)實(shí)現(xiàn)獨(dú)占訪問將更加困難并且開銷更大


3悬襟、按多個(gè)程序?qū)懖僮鞲蓴_本身線程的程度劃分

a.樂觀鎖:認(rèn)為每次讀取數(shù)據(jù)時(shí),不會(huì)進(jìn)行其他寫操作拯刁,如CAS

b.悲觀鎖:認(rèn)為每次讀取數(shù)據(jù)時(shí)脊岳,都會(huì)有寫操作,如synchronized

c.優(yōu)缺點(diǎn)分析

悲觀鎖是指當(dāng)一個(gè)線程獲取鎖時(shí)其他線程只能進(jìn)行阻塞垛玻,并且進(jìn)程掛起和恢復(fù)執(zhí)行過程中也存在著很大的開銷

CAS是項(xiàng)樂觀鎖技術(shù)割捅,當(dāng)多個(gè)線程嘗試使用CAS同時(shí)更新同一個(gè)變量時(shí),只有其中一個(gè)線程能更新變量的值帚桩,而其他線程都失敗亿驾,失敗的線程并不會(huì)被掛起,而是被告知這次競(jìng)爭(zhēng)失敗账嚎,并可以再次嘗試莫瞬。

PS:使用樂觀鎖如果存在大量寫操作,需要不斷重試?yán)速M(fèi)CPU資源


4郭蕉、按多個(gè)線程競(jìng)爭(zhēng)程度劃分

a.偏向鎖:只有一個(gè)申請(qǐng)鎖的線程使用鎖

b.輕量鎖:多個(gè)線程交替使用鎖疼邀,允許短時(shí)間的鎖競(jìng)爭(zhēng)

c.重量鎖:有實(shí)際競(jìng)爭(zhēng),且鎖競(jìng)爭(zhēng)的時(shí)間長(zhǎng)

優(yōu)缺點(diǎn)分析::

1.如果一個(gè)同步方法召锈,沒有多線程競(jìng)爭(zhēng)旁振,并且總是由同一個(gè)線程多次獲取鎖,如果每次還有阻塞線程涨岁,那么對(duì)CPU時(shí)一種資源的浪費(fèi)拐袜,為了解決這類問題,誕生了偏向鎖(偏向鎖只需要在置換ThreadID的時(shí)候依賴一次CAS原子指令梢薪,因?yàn)橹挥幸粋€(gè)線程在競(jìng)爭(zhēng)蹬铺,我們只要去判斷該偏向鎖中的ThreadID是否為當(dāng)前線程即可);

2.輕量級(jí)鎖是通過CAS來(lái)避免進(jìn)入開銷較大的互斥操作,CAS是無(wú)鎖的可以避免線程狀態(tài)切換帶來(lái)的開銷秉撇,但是不適合鎖競(jìng)爭(zhēng)時(shí)間長(zhǎng)(線程計(jì)算慢)甜攀,非常浪費(fèi)CPU資源

3.重量級(jí)鎖更適合時(shí)間長(zhǎng)的情況下使用,可以避免CPU浪費(fèi).

PS:使用Synchronized有進(jìn)行用戶態(tài)到內(nèi)核態(tài)的切換畜疾,這個(gè)過程不是一觸而就的,而是經(jīng)歷了偏向鎖印衔、輕量鎖啡捶、重量鎖三個(gè)過程。


三奸焙、為什么使用Lock

? ? ? ?為了解決synchronized阻塞帶來(lái)的性能問題瞎暑,JDK1.5提供了線程同步工具Lock接口方便實(shí)現(xiàn)各類鎖彤敛,從Lock提供的各類鎖的角度來(lái)說,對(duì)比synchronized這種悲觀鎖要顯得更加豐富和靈活了赌。

(一)Synchronized

synchronized是java中的一個(gè)關(guān)鍵字墨榄,也就是說是Java語(yǔ)言內(nèi)置的特性。

Synchronized是由monitor管程的ObjectMonitor來(lái)實(shí)現(xiàn)請(qǐng)求和等待的:

1.其中ObjectMonitor有兩個(gè)隊(duì)列勿她,用來(lái)保存ObjectWaiter對(duì)象列表(每個(gè)等待鎖的線程都會(huì)被封裝成ObjectWaiter對(duì)象)

????????????_WaitSet

????????????_EntryList

2._Owner指向持有持有Monitor對(duì)象的線程袄秩,當(dāng)多個(gè)線程同時(shí)訪問同一段同步代碼時(shí),首先會(huì)進(jìn)入_EntryList集合

當(dāng)線程獲取到對(duì)象的Monitor后進(jìn)入_Owner區(qū)域逢并,并把Monitor中的owner變量設(shè)置為當(dāng)前線程Monitor中的計(jì)數(shù)器count+1

若當(dāng)前線程執(zhí)行完畢也將釋放monitor(鎖)并復(fù)位變量的值之剧,以便其它線程進(jìn)入獲取monitor(鎖)

3.Synchronized在進(jìn)行重量級(jí)鎖之前會(huì)先歷經(jīng)偏向鎖、輕量級(jí)鎖和自旋鎖

不直接切換成重量級(jí)的鎖的原因是重量級(jí)鎖需要進(jìn)行操作系統(tǒng)Mutex Lock來(lái)實(shí)現(xiàn)砍聊,線程之間的切換需要從用戶狀態(tài)到核心態(tài)

4.Synchronized缺陷(重量級(jí)鎖/悲觀鎖的缺陷)

a.當(dāng)一個(gè)代碼塊被Synchronized修飾了背稼,如果一個(gè)線程獲取了對(duì)應(yīng)的鎖,并執(zhí)行該代碼塊時(shí)玻蝌,其他線程便只能一直等待蟹肘,等待獲取鎖的線程釋放鎖,而這里獲取鎖的線程釋放鎖只會(huì)有兩種情況

????獲取鎖的線程執(zhí)行完了該代碼塊俯树,然后線程釋放對(duì)鎖的占有帘腹;

????線程執(zhí)行發(fā)生異常,此時(shí)JVM會(huì)讓線程自動(dòng)釋放鎖聘萨。

b.若這個(gè)鎖獲取的線程由于要等待IO或其他原因(如調(diào)用sleep方法)被阻塞了竹椒,但是又沒有釋放鎖,其他線程便只能等待

c.程序執(zhí)行效率低下

Synchronized不具備的特性

(二)Lock和Synchronized的區(qū)別

1米辐、Synchronized是屬于虛擬機(jī)層面胸完,Lock是屬于api層面,前者是關(guān)鍵字翘贮,后者是java實(shí)現(xiàn)的類赊窥。也就是說前者是在JVM內(nèi)部實(shí)現(xiàn)得,Lock是在語(yǔ)言層面實(shí)現(xiàn)的狸页。

2锨能、JVM內(nèi)部使用的是monitorenter和monitorexit指令實(shí)現(xiàn);Lock基本的是用state變量來(lái)判斷是否被鎖芍耘。

3址遇、Synchronized不用手動(dòng)釋放鎖,代碼執(zhí)行完了自動(dòng)釋放斋竞,而Lock要手動(dòng)釋放倔约。lock()和unlock()方法必須配對(duì)使用。

4坝初、Synchronized是非公平鎖浸剩,Lock默認(rèn)是非公平鎖钾军,但是可以設(shè)置成公平鎖。

5绢要、Synchronized不能中斷吏恭,必須拋出異常或者代碼執(zhí)行完重罪。而Lock可以中斷氧枣,這也是Lock的特點(diǎn):

(1)可以設(shè)置超時(shí)方法tryLock(long timeout, TimeUnit unit);

(2)上鎖的時(shí)候可以上可中斷鎖:lockInterruptibly()年缎,線程阻塞在鎖著的時(shí)候可以在其它線程中調(diào)用interrupter()方法中斷蓬衡,拋出InterruptedException異常以供處理碎捺,如下例:

lock中斷 ?

Synchronized喚醒線程時(shí)只能隨機(jī)喚醒,Lock可以搭配Condition實(shí)現(xiàn)精準(zhǔn)喚醒某個(gè)線程惨篱。通過聲明多個(gè)Condition來(lái)實(shí)現(xiàn)盏筐,喚醒時(shí)喚醒阻塞在某個(gè)Condition上的線程。


四砸讳、Lock API

1琢融、lock()?獲得鎖,否則一直等待

2簿寂、unlock()?釋放鎖

3漾抬、tryLock()?判斷鎖狀態(tài),鎖被占用就返回false,否則返回true

4常遂、tryLock(Long time, TimeUnit unie)?比起tryLock()添加一個(gè)時(shí)間期限判斷

5纳令、lockInterruptibly()?此種獲取鎖的方式,鎖被占用的情況下拋出異常克胳,直接終端平绩,可以去做其他處理

6、Condition newCondition()?通知組件:具有阻塞與喚醒功能


五漠另、Condition

Object類中的wait()捏雌、notify()、notifyAll()方法實(shí)現(xiàn)了線程之間的通信笆搓,而Condition類中的await()性湿、signal()、signalAll()方法也實(shí)現(xiàn)了相似的功能满败。通過Condition能夠精細(xì)的控制多線程的休眠與喚醒肤频, 對(duì)于一個(gè)鎖,我們可以為多個(gè)線程間建立不同的Condition算墨。? ? ??

ConditionObject是同步器AbstractQueuedSynchronizer的內(nèi)部類宵荒,每個(gè)Condition對(duì)象都包含著一個(gè)隊(duì)列,該隊(duì)列是Condition對(duì)象實(shí)現(xiàn)等待/通知功能的關(guān)鍵

同步隊(duì)列:AQS的同步排隊(duì)用了一個(gè)隱式的雙向隊(duì)列,同步隊(duì)列的每個(gè)節(jié)點(diǎn)是一個(gè)AbstractQueuedSynchronizer.Node實(shí)例

等待隊(duì)列:Conditon的等待隊(duì)列用了一個(gè)隱式的單向隊(duì)列骇扇,等待隊(duì)列的每個(gè)節(jié)點(diǎn)是一個(gè)AbstractQueuedSynchronizer.Node實(shí)例

總結(jié):

1:整個(gè)過程是節(jié)點(diǎn)在同步隊(duì)列和等待隊(duì)列中來(lái)回移動(dòng)實(shí)現(xiàn)的

2:每當(dāng)一個(gè)線程調(diào)用Condition.await()方法,那么該線程會(huì)釋放鎖面粮,構(gòu)造成一個(gè)Node節(jié)點(diǎn)加入到等待隊(duì)列的隊(duì)尾少孝,自旋判斷如果當(dāng)前節(jié)點(diǎn)沒有在同步隊(duì)列上則將當(dāng)前線程阻塞

3:調(diào)用Condition的signal()方法,會(huì)將節(jié)點(diǎn)移到同步隊(duì)列中熬苍,但不一定在隊(duì)首

4:如果退出自旋說明當(dāng)前節(jié)點(diǎn)已經(jīng)在同步隊(duì)列上稍走。通過acquireQueued將阻塞直到當(dāng)前節(jié)點(diǎn)成為隊(duì)首,即當(dāng)前線程獲得了鎖柴底。然后await()方法就可以退出了婿脸,讓線程繼續(xù)執(zhí)行await()后的代碼


六、AbstractQueuedSynchronizer(AQS)

AQS是locks的核心柄驻,就好像前端控制器對(duì)于springMVC來(lái)說一樣狐树。

AQS提供一個(gè)框架,一個(gè)FIFO的等待隊(duì)列和一個(gè)代表狀態(tài)的int值鸿脓,子類需要定義這個(gè)狀態(tài)的protected方法抑钟,定義什么狀態(tài)獲取到狀態(tài)以及釋放鎖狀態(tài),該類方法提供所有入隊(duì)和阻塞機(jī)制野哭,AQS框架提供了一套通用的機(jī)制來(lái)管理同步狀態(tài)在塔、阻塞/喚醒線程、管理等待隊(duì)列,是JUC上大多數(shù)同步器的基礎(chǔ):

1拨黔、模板模式:定義一個(gè)操作中算法的骨架蛔溃,將一些步驟延遲到子類中。

2篱蝇、模板方法:AQS的一組模板方法贺待,直接調(diào)用同步方法組件

模板方法使得子類可以不改變算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟

AQS的模版方法

3、同步組件:程序員需要選擇覆蓋實(shí)現(xiàn)以下方法來(lái)時(shí)下能同步狀態(tài)的管理

同步組件

4态兴、同步狀態(tài):同步狀態(tài)的管理配合同步組件使用

同步狀態(tài)

CLH同步隊(duì)列是一個(gè)FIFO雙向隊(duì)列狠持,AQS依賴它來(lái)完成同步狀態(tài)的管理,在CLH同步隊(duì)列中瞻润,一個(gè)節(jié)點(diǎn)表示一個(gè)線程

總結(jié):線程會(huì)首先嘗試獲取鎖喘垂,失敗則將當(dāng)前線程以及等待狀態(tài)等信息包成一個(gè)Node節(jié)點(diǎn)加到CLH隊(duì)列來(lái)管理鎖,接著通過死循環(huán)嘗試獲取鎖绍撞,在拿到鎖為止會(huì)不斷阻塞正勒,等到線程釋放鎖時(shí),會(huì)喚醒隊(duì)列中的后繼線程


七傻铣、ReentrantLock

語(yǔ)法:ReentrantLock(boolean fair) 創(chuàng)建一個(gè)(公平/非公平)的具有可重入性質(zhì)的對(duì)象

1章贞、非公平(默認(rèn))

ReentrantLock 非公平鎖 ?

(1)通過CAS加鎖,如果成功則setExclusiveOwnerThread(設(shè)置獨(dú)占鎖)非洲;如果不成功代表已經(jīng)持有鎖是一個(gè)重入的線程

(2)acquire為AbstractQueuedSynchronizer的模塊方法鸭限,獲取線程并調(diào)用compareAndSetState進(jìn)行設(shè)置(加鎖)蜕径,加鎖失敗代表鎖已經(jīng)被占用,則判斷當(dāng)前線程是否是鎖的持有者败京,如果是則代表是一把重入鎖兜喻,通過setState不斷累加鎖重入的次數(shù)。

釋放鎖

如果當(dāng)前線程不是鎖的持有者赡麦,拋出異常朴皆,鎖紀(jì)錄為0代表釋放全部,返回true,否則設(shè)置同步狀態(tài)返回false

2泛粹、公平鎖

ReentrantLock 公平鎖

調(diào)用hasQueuedPredecessors判斷:當(dāng)前線程不是同步隊(duì)列有其他線程優(yōu)先則返回false不能獲取鎖


八遂铡、ReentrantReadWriteLock

ReentrantReadWriteLock? 特性

ReentrantReadWriteLock為讀寫鎖,對(duì)于讀操作是共享鎖晶姊,對(duì)于寫操作是獨(dú)占鎖

讀寫鎖是依賴AQS框架實(shí)現(xiàn)的共享鎖與排它鎖扒接,AQS 維護(hù)一個(gè)state是32位的,內(nèi)部類Sync采用一套運(yùn)算規(guī)則们衙,實(shí)現(xiàn)了高位保存共享鎖珠增,低位保存獨(dú)占鎖的一套邏輯

源碼大家感興趣可以自己去看看

實(shí)例:

實(shí)例

結(jié)果運(yùn)行的效果是:先每隔 一秒打印一次?ti,說明寫寫互斥(每隔1s打涌嘲)蒂教,寫讀互斥(打印時(shí)不輸出讀操作的輸出),如果把兩個(gè)循環(huán)交換順序脆荷,可以看到凝垛,程序先等一秒,然后一次性輸出十次數(shù)據(jù)蜓谋,接著再一秒一次打印?ti梦皮, 說明讀讀不互斥(一次性全輸出),讀寫互斥(讀操作的sleep 1s的過程中桃焕,并沒有輸出寫操作的輸出)剑肯。


九、LockSupport

Object類的wait/notify機(jī)制相比观堂,park/unpark有兩個(gè)優(yōu)點(diǎn):1. 以thread為操作對(duì)象更符合阻塞線程的直觀定義让网;2. 操作更精準(zhǔn),可以準(zhǔn)確地喚醒某一個(gè)線程

每個(gè)線程都有一個(gè)許可(permit)师痕,permit只有兩個(gè)值1和0,默認(rèn)是0,通過park/unpark設(shè)置

補(bǔ)充知識(shí):為什么已經(jīng)有ReentrantReadWriteLock,jdk1.8還要引入StampedLock?

JDK1.8引入StampedLock溃睹,解決如果一直有讀操作導(dǎo)致寫操作饑餓的問題。

讀操作一直都能搶占到CPU時(shí)間片胰坟,而寫操作一直搶不了因篇,可能導(dǎo)致寫的饑餓問題,正因?yàn)镽eentrantReadWriteLock出現(xiàn)了讀和寫是互斥的情況,這個(gè)地方需要優(yōu)化竞滓,因此就出現(xiàn)了StampedLock

StampedLock源碼

tryOptimisticRead():當(dāng)前沒有線程持有寫鎖咐吼,則簡(jiǎn)單的返回一個(gè)非 0 的 stamp 版本信息

validate():檢測(cè)樂觀讀版本號(hào)是否變化

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市商佑,隨后出現(xiàn)的幾起案子汽烦,更是在濱河造成了極大的恐慌,老刑警劉巖莉御,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異俗冻,居然都是意外死亡礁叔,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門迄薄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)琅关,“玉大人,你說我怎么就攤上這事讥蔽』烈祝” “怎么了?”我有些...
    開封第一講書人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵冶伞,是天一觀的道長(zhǎng)新症。 經(jīng)常有香客問我,道長(zhǎng)响禽,這世上最難降的妖魔是什么徒爹? 我笑而不...
    開封第一講書人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮芋类,結(jié)果婚禮上隆嗅,老公的妹妹穿的比我還像新娘。我一直安慰自己侯繁,他們只是感情好胖喳,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著贮竟,像睡著了一般丽焊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上咕别,一...
    開封第一講書人閱讀 51,590評(píng)論 1 305
  • 那天粹懒,我揣著相機(jī)與錄音,去河邊找鬼顷级。 笑死凫乖,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播帽芽,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼删掀,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了导街?” 一聲冷哼從身側(cè)響起披泪,我...
    開封第一講書人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎搬瑰,沒想到半個(gè)月后款票,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡泽论,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年艾少,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片翼悴。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡缚够,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鹦赎,到底是詐尸還是另有隱情谍椅,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布古话,位于F島的核電站雏吭,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏陪踩。R本人自食惡果不足惜思恐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望膊毁。 院中可真熱鬧胀莹,春花似錦、人聲如沸婚温。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)栅螟。三九已至荆秦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間力图,已是汗流浹背步绸。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吃媒,地道東北人瓤介。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓吕喘,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親刑桑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子氯质,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355