公平鎖java代碼 java實(shí)現(xiàn)公平鎖

Java鎖有哪些種類(lèi),以及區(qū)別

一、公平鎖/非公平鎖

讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來(lái)自于我們對(duì)這個(gè)行業(yè)的熱愛(ài)。我們立志把好的技術(shù)通過(guò)有效、簡(jiǎn)單的方式提供給客戶,將通過(guò)不懈努力成為客戶在信息化領(lǐng)域值得信任、有價(jià)值的長(zhǎng)期合作伙伴,公司提供的服務(wù)項(xiàng)目有:國(guó)際域名空間、網(wǎng)絡(luò)空間、營(yíng)銷(xiāo)軟件、網(wǎng)站建設(shè)、鎮(zhèn)平網(wǎng)站維護(hù)、網(wǎng)站推廣。

公平鎖是指多個(gè)線程按照申請(qǐng)鎖的順序來(lái)獲取鎖。

非公平鎖是指多個(gè)線程獲取鎖的順序并不是按照申請(qǐng)鎖的順序,有可能后申請(qǐng)的線程比先申請(qǐng)的線程優(yōu)先獲取鎖。有可能,會(huì)造成優(yōu)先級(jí)反轉(zhuǎn)或者饑餓現(xiàn)象。

對(duì)于Java ReentrantLock而言,通過(guò)構(gòu)造函數(shù)指定該鎖是否是公平鎖,默認(rèn)是非公平鎖。非公平鎖的優(yōu)點(diǎn)在于吞吐量比公平鎖大。

對(duì)于Synchronized而言,也是一種非公平鎖。由于其并不像ReentrantLock是通過(guò)AQS的來(lái)實(shí)現(xiàn)線程調(diào)度,所以并沒(méi)有任何辦法使其變成公平鎖。

二、可重入鎖

可重入鎖又名遞歸鎖,是指在同一個(gè)線程在外層方法獲取鎖的時(shí)候,在進(jìn)入內(nèi)層方法會(huì)自動(dòng)獲取鎖。說(shuō)的有點(diǎn)抽象,下面會(huì)有一個(gè)代碼的示例。

對(duì)于Java ReentrantLock而言, 他的名字就可以看出是一個(gè)可重入鎖,其名字是Re entrant Lock重新進(jìn)入鎖。

對(duì)于Synchronized而言,也是一個(gè)可重入鎖??芍厝腈i的一個(gè)好處是可一定程度避免死鎖。

synchronized void setA() throws Exception{

Thread.sleep(1000);

setB();

}

synchronized void setB() throws Exception{

Thread.sleep(1000);

}

上面的代碼就是一個(gè)可重入鎖的一個(gè)特點(diǎn),如果不是可重入鎖的話,setB可能不會(huì)被當(dāng)前線程執(zhí)行,可能造成死鎖。

三、獨(dú)享鎖/共享鎖

獨(dú)享鎖是指該鎖一次只能被一個(gè)線程所持有。

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

對(duì)于Java

ReentrantLock而言,其是獨(dú)享鎖。但是對(duì)于Lock的另一個(gè)實(shí)現(xiàn)類(lèi)ReadWriteLock,其讀鎖是共享鎖,其寫(xiě)鎖是獨(dú)享鎖。

讀鎖的共享鎖可保證并發(fā)讀是非常高效的,讀寫(xiě),寫(xiě)讀 ,寫(xiě)寫(xiě)的過(guò)程是互斥的。

獨(dú)享鎖與共享鎖也是通過(guò)AQS來(lái)實(shí)現(xiàn)的,通過(guò)實(shí)現(xiàn)不同的方法,來(lái)實(shí)現(xiàn)獨(dú)享或者共享。

對(duì)于Synchronized而言,當(dāng)然是獨(dú)享鎖。

四、互斥鎖/讀寫(xiě)鎖

上面講的獨(dú)享鎖/共享鎖就是一種廣義的說(shuō)法,互斥鎖/讀寫(xiě)鎖就是具體的實(shí)現(xiàn)。

互斥鎖在Java中的具體實(shí)現(xiàn)就是ReentrantLock

讀寫(xiě)鎖在Java中的具體實(shí)現(xiàn)就是ReadWriteLock

五、樂(lè)觀鎖/悲觀鎖

樂(lè)觀鎖與悲觀鎖不是指具體的什么類(lèi)型的鎖,而是指看待并發(fā)同步的角度。

悲觀鎖認(rèn)為對(duì)于同一個(gè)數(shù)據(jù)的并發(fā)操作,一定是會(huì)發(fā)生修改的,哪怕沒(méi)有修改,也會(huì)認(rèn)為修改。因此對(duì)于同一個(gè)數(shù)據(jù)的并發(fā)操作,悲觀鎖采取加鎖的形式。悲觀的認(rèn)為,不加鎖的并發(fā)操作一定會(huì)出問(wèn)題。

樂(lè)觀鎖則認(rèn)為對(duì)于同一個(gè)數(shù)據(jù)的并發(fā)操作,是不會(huì)發(fā)生修改的。在更新數(shù)據(jù)的時(shí)候,會(huì)采用嘗試更新,不斷重新的方式更新數(shù)據(jù)。樂(lè)觀的認(rèn)為,不加鎖的并發(fā)操作是沒(méi)有事情的。

從上面的描述我們可以看出,悲觀鎖適合寫(xiě)操作非常多的場(chǎng)景,樂(lè)觀鎖適合讀操作非常多的場(chǎng)景,不加鎖會(huì)帶來(lái)大量的性能提升。

悲觀鎖在Java中的使用,就是利用各種鎖。

樂(lè)觀鎖在Java中的使用,是無(wú)鎖編程,常常采用的是CAS算法,典型的例子就是原子類(lèi),通過(guò)CAS自旋實(shí)現(xiàn)原子操作的更新。

六、分段鎖

分段鎖其實(shí)是一種鎖的設(shè)計(jì),并不是具體的一種鎖,對(duì)于ConcurrentHashMap而言,其并發(fā)的實(shí)現(xiàn)就是通過(guò)分段鎖的形式來(lái)實(shí)現(xiàn)高效的并發(fā)操作。

我們以ConcurrentHashMap來(lái)說(shuō)一下分段鎖的含義以及設(shè)計(jì)思想,ConcurrentHashMap中的分段鎖稱(chēng)為Segment,它即類(lèi)似于HashMap(JDK7與JDK8中HashMap的實(shí)現(xiàn))的結(jié)構(gòu),即內(nèi)部擁有一個(gè)Entry數(shù)組,數(shù)組中的每個(gè)元素又是一個(gè)鏈表;同時(shí)又是一個(gè)ReentrantLock(Segment繼承了ReentrantLock)。

當(dāng)需要put元素的時(shí)候,并不是對(duì)整個(gè)hashmap進(jìn)行加鎖,而是先通過(guò)hashcode來(lái)知道他要放在那一個(gè)分段中,然后對(duì)這個(gè)分段進(jìn)行加鎖,所以當(dāng)多線程put的時(shí)候,只要不是放在一個(gè)分段中,就實(shí)現(xiàn)了真正的并行的插入。

但是,在統(tǒng)計(jì)size的時(shí)候,可就是獲取hashmap全局信息的時(shí)候,就需要獲取所有的分段鎖才能統(tǒng)計(jì)。

分段鎖的設(shè)計(jì)目的是細(xì)化鎖的粒度,當(dāng)操作不需要更新整個(gè)數(shù)組的時(shí)候,就僅僅針對(duì)數(shù)組中的一項(xiàng)進(jìn)行加鎖操作。

七、偏向鎖/輕量級(jí)鎖/重量級(jí)鎖

這三種鎖是指鎖的狀態(tài),并且是針對(duì)Synchronized。在Java

5通過(guò)引入鎖升級(jí)的機(jī)制來(lái)實(shí)現(xiàn)高效Synchronized。這三種鎖的狀態(tài)是通過(guò)對(duì)象監(jiān)視器在對(duì)象頭中的字段來(lái)表明的。

偏向鎖是指一段同步代碼一直被一個(gè)線程所訪問(wèn),那么該線程會(huì)自動(dòng)獲取鎖。降低獲取鎖的代價(jià)。

輕量級(jí)鎖是指當(dāng)鎖是偏向鎖的時(shí)候,被另一個(gè)線程所訪問(wèn),偏向鎖就會(huì)升級(jí)為輕量級(jí)鎖,其他線程會(huì)通過(guò)自旋的形式嘗試獲取鎖,不會(huì)阻塞,提高性能。

重量級(jí)鎖是指當(dāng)鎖為輕量級(jí)鎖的時(shí)候,另一個(gè)線程雖然是自旋,但自旋不會(huì)一直持續(xù)下去,當(dāng)自旋一定次數(shù)的時(shí)候,還沒(méi)有獲取到鎖,就會(huì)進(jìn)入阻塞,該鎖膨脹為重量級(jí)鎖。重量級(jí)鎖會(huì)讓其他申請(qǐng)的線程進(jìn)入阻塞,性能降低。

八、自旋鎖

在Java中,自旋鎖是指嘗試獲取鎖的線程不會(huì)立即阻塞,而是采用循環(huán)的方式去嘗試獲取鎖,這樣的好處是減少線程上下文切換的消耗,缺點(diǎn)是循環(huán)會(huì)消耗CPU。

典型的自旋鎖實(shí)現(xiàn)的例子,可以參考自旋鎖的實(shí)現(xiàn)

Java中有哪些鎖,區(qū)別是什么

【1】公平所和非公平所。

公平鎖:是指按照申請(qǐng)鎖的順序來(lái)獲取鎖,

非公平所:線程獲取鎖的順序不一定按照申請(qǐng)鎖的順序來(lái)的。

//默認(rèn)是不公平鎖,傳入true為公平鎖,否則為非公平鎖

ReentrantLock reentrantLock = new ReetrantLock();

1

2

【2】共享鎖和獨(dú)享鎖

獨(dú)享鎖:一次只能被一個(gè)線程所訪問(wèn)

共享鎖:線程可以被多個(gè)線程所持有。

ReadWriteLock 讀鎖是共享鎖,寫(xiě)鎖是獨(dú)享鎖。

【3】樂(lè)觀鎖和悲觀鎖。

樂(lè)觀鎖:對(duì)于一個(gè)數(shù)據(jù)的操作并發(fā),是不會(huì)發(fā)生修改的。在更新數(shù)據(jù)的時(shí)候,會(huì)嘗試采用更新,不斷重入的方式,更新數(shù)據(jù)。

悲觀鎖:對(duì)于同一個(gè)數(shù)據(jù)的并發(fā)操作,是一定會(huì)發(fā)生修改的。因此對(duì)于同一個(gè)數(shù)據(jù)的并發(fā)操作,悲觀鎖采用加鎖的形式。悲觀鎖認(rèn)為,不加鎖的操作一定會(huì)出問(wèn)題,

【4】分段鎖

1.7及之前的concurrenthashmap。并發(fā)操作就是分段鎖,其思想就是讓鎖的粒度變小。

【5】偏向鎖是指一段同步代碼一直被一個(gè)線程所訪問(wèn),那么該線程會(huì)自動(dòng)獲取鎖。降低獲取鎖的代價(jià)

輕量級(jí)鎖

重量級(jí)鎖

【6】自旋鎖

自旋鎖

什么是Java中的公平鎖

首先Java中的ReentrantLock 默認(rèn)的lock()方法采用的是非公平鎖。

也就是不用考慮其他在排隊(duì)的線程的感受,lock()的時(shí)候直接詢(xún)問(wèn)是否可以獲取鎖,而不用在隊(duì)尾排隊(duì)。

下面分析下公平鎖的具體實(shí)現(xiàn)。

重點(diǎn)關(guān)注java.util.concurrent.locks.AbstractQueuedSynchronizer類(lèi)

幾乎所有l(wèi)ocks包下的工具類(lèi)鎖都包含了該類(lèi)的static子類(lèi),足以可見(jiàn)這個(gè)類(lèi)在java并發(fā)鎖工具類(lèi)當(dāng)中的地位。

這個(gè)類(lèi)提供了對(duì)操作系統(tǒng)層面線程操作方法的封裝調(diào)用,可以幫助并發(fā)設(shè)計(jì)者設(shè)計(jì)出很多優(yōu)秀的API

ReentrantLock當(dāng)中的lock()方法,是通過(guò)static 內(nèi)部類(lèi)sync來(lái)進(jìn)行鎖操作

public void lock()

{

sync.lock();

}

//定義成final型的成員變量,在構(gòu)造方法中進(jìn)行初始化

private final Sync sync;

//無(wú)參數(shù)默認(rèn)非公平鎖

public ReentrantLock()

{

sync = new NonfairSync();

}

//根據(jù)參數(shù)初始化為公平鎖或者非公平鎖

public ReentrantLock(boolean fair)

{

sync = fair ? new FairSync() : new NonfairSync();

}

java中的非公平鎖不怕有的線程一直得不到執(zhí)行嗎

首先來(lái)看公平鎖和非公平鎖,我們默認(rèn)使用的鎖是非公平鎖,只有當(dāng)我們顯示設(shè)置為公平鎖的情況下,才會(huì)使用公平鎖,下面我們簡(jiǎn)單看一下公平鎖的源碼,如果等待隊(duì)列中沒(méi)有節(jié)點(diǎn)在等待,則占有鎖,如果已經(jīng)存在等待節(jié)點(diǎn),則返回失敗,由后面的程序去將此線程加入等待隊(duì)列

通過(guò)上面的代碼,我們可以推斷,當(dāng)使用公平鎖的情況下,并且同一個(gè)線程的執(zhí)行時(shí)間較長(zhǎng)時(shí),線程內(nèi)部進(jìn)行了多次的鎖的獲取和釋放,效率非常低下,可以參加Lesson8中的demo:

demo Lesson8LockIntPerform:在使用ReentrantLock加非公平鎖的情況下100個(gè)線程循環(huán)下單數(shù)為:857239882

demo Lesson8LockIntPerform:在使用ReentrantLock加非公平鎖的情況下100個(gè)線程循環(huán)下單數(shù)為:860364303

demo Lesson8LockFairIntPerform:在使用ReentrantLock加公平鎖的情況下100個(gè)線程循環(huán)下單數(shù)為:19153640

demo Lesson8LockFairIntPerform:在使用ReentrantLock加公平鎖的情況下100個(gè)線程循環(huán)下單數(shù)為:19076567

上面的demo中,在使用公平鎖的情況下性能明顯降低,非公平鎖的性能是公平鎖性能的幾十倍以上,這和公平鎖每次試圖占有鎖時(shí),都必須先要進(jìn)等待隊(duì)列,按照FIFO的順序去獲取鎖,因此在我們的實(shí)驗(yàn)情景下,使用公平鎖的線程進(jìn)行了頻繁切換,而頻繁切換線程,性能必然會(huì)下降的厲害,這也告誡了我們?cè)趯?shí)際的開(kāi)發(fā)過(guò)程中,在需要使用公平鎖的情景下,務(wù)必要考慮線程的切換頻率。

接下來(lái)我們來(lái)看一下讀寫(xiě)鎖,通過(guò)看讀寫(xiě)鎖的實(shí)現(xiàn)源碼,我們可以發(fā)現(xiàn),讀鎖和寫(xiě)鎖共用同一個(gè)等待隊(duì)列,那么在采用非公平鎖的情況下,如果讀鎖的線程執(zhí)行時(shí)間比較長(zhǎng),并且讀鎖的并發(fā)比較高,那么寫(xiě)鎖的線程便永遠(yuǎn)都拿不到鎖,那么實(shí)際的情況會(huì)不會(huì)是這樣呢?

demo?Lesson3WriteReadLock:此demo的讀線程在不斷的占用讀鎖,按照推論,寫(xiě)鎖的線程是沒(méi)有機(jī)會(huì)獲取到鎖的,但是實(shí)際情況是寫(xiě)鎖的線程可以正常的獲取到鎖,那么是什么原因使得寫(xiě)鎖的線程可以獲取到鎖的了?通過(guò)查看源代碼,會(huì)發(fā)現(xiàn)有這樣的一個(gè)方法:

上面的方法,實(shí)現(xiàn)了一個(gè)新的讀線程獲取鎖的中斷,它會(huì)讀取等待隊(duì)列中下一個(gè)等待鎖的線程,如果它是獲取寫(xiě)鎖的線程,那么此方法返回為真,調(diào)用它的程序會(huì)把這個(gè)試圖獲取讀鎖的線程加入到等待隊(duì)列,從而終止了讀線程一直都在占有鎖的情況。

誰(shuí)用鎖使用鎖

為什么加鎖?

面試中有很多時(shí)候會(huì)問(wèn)到,為什么加鎖?加鎖是起到什么作用?

而實(shí)際上在我們的開(kāi)發(fā)過(guò)程中會(huì)出現(xiàn)并發(fā)的情況,比如說(shuō)兩個(gè)人幾乎同時(shí)點(diǎn)擊了某一個(gè)按鈕,這個(gè)時(shí)候就可以簡(jiǎn)單的理解成并發(fā),那么到底誰(shuí)先誰(shuí)后? 程序中就很可能出現(xiàn)錯(cuò)誤,當(dāng)資源出現(xiàn)共享的時(shí)候,就會(huì)開(kāi)始涉及到并發(fā)了,這個(gè)時(shí)候我們就可能會(huì)用到鎖了,來(lái)鎖住某一個(gè)資源,等我用過(guò)之后,你才能動(dòng)。 這就是為什么使用鎖。

鎖的分類(lèi)

公平鎖/非公平鎖

可重入鎖

獨(dú)享鎖/共享鎖

互斥鎖/讀寫(xiě)鎖

樂(lè)觀鎖/悲觀鎖

分段鎖

偏向鎖/輕量級(jí)鎖/重量級(jí)鎖

自旋鎖

第一次分享,我們就先說(shuō)這個(gè)公平鎖和非公平鎖。之后會(huì)在后序的文章中繼續(xù)解析!

何為公平?何為非公平?在我們?nèi)粘I钪械睦斫獠痪褪菍?duì)等的就是公平,不對(duì)等的就是不公平? 其實(shí)差不多的。

公平鎖是指多個(gè)線程按照申請(qǐng)鎖的順序來(lái)獲取鎖

非公平鎖是指多個(gè)線程獲取鎖的順序并不是按照申請(qǐng)鎖的順序,有可能后申請(qǐng)的線程比先申請(qǐng)的線程優(yōu)先獲取鎖。有可能,會(huì)造成優(yōu)先級(jí)反轉(zhuǎn)或者饑餓現(xiàn)象。

在JAVA的代碼中什么是公平鎖什么又是非公平的鎖呢?

一種是使用Java自帶的關(guān)鍵字synchronized對(duì)相應(yīng)的類(lèi)或者方法以及代碼塊進(jìn)行加鎖,

而另一種是ReentrantLock,前者只能是非公平鎖,而后者是默認(rèn)非公平但可實(shí)現(xiàn)公平的一把鎖。

上面的類(lèi)圖看起來(lái)很不舒服,因?yàn)殛P(guān)于ReentrantLock這個(gè)鎖,確實(shí)是沒(méi)有很好的配圖,我們可以自己畫(huà)出來(lái)理解一下

我們先看非公平鎖,我畫(huà)圖大家理解一下,就像公共廁所,不要嫌棄惡心,但是絕對(duì)容易理解

上面這幅圖,加入說(shuō)圖中的管理員是Lock,然后現(xiàn)在A來(lái)了,說(shuō)我要去廁所,這時(shí)候管理員一看,廁所沒(méi)人,那好你進(jìn)去把,然后A就進(jìn)去了。

這個(gè)時(shí)候WC里面是有A的,正在進(jìn)行式,這時(shí)候B來(lái)了,B也想去廁所

但是這個(gè)時(shí)候WC里面是有A的,然后管理員Lock看了一下,里面有人,排隊(duì)把。。。

然后這B就得憋著,去進(jìn)入隊(duì)列去排隊(duì),然后又來(lái)了個(gè)C,這時(shí)候A還在里面,C只能也去排隊(duì),

就是這個(gè)樣子的

這時(shí)候又過(guò)了一小會(huì)來(lái)了個(gè)D,也想去WC,這時(shí)候A恰好結(jié)束了,

這時(shí)候非公平鎖就上場(chǎng)了,Lock管理員一看,里面沒(méi)人,D你進(jìn)去把,這時(shí)候就是這樣的。

當(dāng)前文章:公平鎖java代碼 java實(shí)現(xiàn)公平鎖
URL鏈接:http://muchs.cn/article40/docsjho.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站建設(shè)、網(wǎng)站收錄、企業(yè)網(wǎng)站制作、虛擬主機(jī)、建站公司、商城網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都seo排名網(wǎng)站優(yōu)化