java高并發(fā)系列-第2天:并發(fā)級(jí)別

由于臨界區(qū)的存在,多線程之間的并發(fā)必須受到控制。根據(jù)控制并發(fā)的策略,我們可以把并發(fā)的級(jí)別分為阻塞、無饑餓無障礙、無鎖無等待幾種。

我們提供的服務(wù)有:做網(wǎng)站、網(wǎng)站制作、微信公眾號(hào)開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、蕪湖ssl等。為1000+企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的蕪湖網(wǎng)站制作公司

阻塞

一個(gè)線程是阻塞的,那么在其他線程釋放資源之前,當(dāng)前線程無法繼續(xù)執(zhí)行。當(dāng)我們使用synchronized關(guān)鍵字或者重入鎖時(shí),我們得到的就是阻塞的線程。

synchronize關(guān)鍵字和重入鎖都試圖在執(zhí)行后續(xù)代碼前,得到臨界區(qū)的鎖,如果得不到,線程就會(huì)被掛起等待,直到占有了所需資源為止。

無饑餓(Starvation-Free)

如果線程之間是有優(yōu)先級(jí)的,那么線程調(diào)度的時(shí)候總是會(huì)傾向于先滿足高優(yōu)先級(jí)的線程。也就是說,對(duì)于同一個(gè)資源的分配,是不公平的!圖1.7中顯示了非公平鎖與公平鎖兩種情況(五角星表示高優(yōu)先級(jí)線程)。對(duì)于非公平鎖來說,系統(tǒng)允許高優(yōu)先級(jí)的線程插隊(duì)。這樣有可能導(dǎo)致低優(yōu)先級(jí)線程產(chǎn)生饑餓。但如果鎖是公平的,按照先來后到的規(guī)則,那么饑餓就不會(huì)產(chǎn)生,不管新來的線程優(yōu)先級(jí)多高,要想獲得資源,就必須乖乖排隊(duì),這樣所有的線程都有機(jī)會(huì)執(zhí)行。

java高并發(fā)系列 - 第2天:并發(fā)級(jí)別

無障礙(Obstruction-Free)

無障礙是一種最弱的非阻塞調(diào)度。兩個(gè)線程如果無障礙地執(zhí)行,那么不會(huì)因?yàn)榕R界區(qū)的問題導(dǎo)致一方被掛起。換言之,大家都可以大搖大擺地進(jìn)入臨界區(qū)了。那么大家一起修改共享數(shù)據(jù),把數(shù)據(jù)改壞了怎么辦呢?對(duì)于無障礙的線程來說,一旦檢測(cè)到這種情況,它就會(huì)立即對(duì)自己所做的修改進(jìn)行回滾,確保數(shù)據(jù)安全。但如果沒有數(shù)據(jù)競(jìng)爭(zhēng)發(fā)生,那么線程就可以順利完成自己的工作,走出臨界區(qū)。

如果說阻塞的控制方式是悲觀策略,也就是說,系統(tǒng)認(rèn)為兩個(gè)線程之間很有可能發(fā)生不幸的沖突,因此以保護(hù)共享數(shù)據(jù)為第一優(yōu)先級(jí),相對(duì)來說,非阻塞的調(diào)度就是一種樂觀的策略。它認(rèn)為多個(gè)線程之間很有可能不會(huì)發(fā)生沖突,或者說這種概率不大。因此大家都應(yīng)該無障礙地執(zhí)行,但是一旦檢測(cè)到?jīng)_突,就應(yīng)該進(jìn)行回滾。

從這個(gè)策略中也可以看到,無障礙的多線程程序并不一定能順暢運(yùn)行。因?yàn)楫?dāng)臨界區(qū)中存在嚴(yán)重的沖突時(shí),所有的線程可能都會(huì)不斷地回滾自己的操作,而沒有一個(gè)線程可以走出臨界區(qū)。這種情況會(huì)影響系統(tǒng)的正常執(zhí)行。所以,我們可能會(huì)非常希望在這一堆線程中,至少可以有一個(gè)線程能夠在有限的時(shí)間內(nèi)完成自己的操作,而退出臨界區(qū)。至少這樣可以保證系統(tǒng)不會(huì)在臨界區(qū)中進(jìn)行無限的等待。

一種可行的無障礙實(shí)現(xiàn)可以依賴一個(gè)"一致性標(biāo)記"來實(shí)現(xiàn)。線程在操作之前,先讀取并保存這個(gè)標(biāo)記,在操作完成后,再次讀取,檢查這個(gè)標(biāo)記是否被更改過,如果兩者是一致的,則說明資源訪問沒有沖突。如果不一致,則說明資源可能在操作過程中與其他線程沖突,需要重試操作。而任何對(duì)資源有修改操作的線程,在修改數(shù)據(jù)前,都需要更新這個(gè)一致性標(biāo)記,表示數(shù)據(jù)不再安全。

數(shù)據(jù)庫中樂觀鎖,應(yīng)該比較熟悉,表中需要一個(gè)字段version(版本號(hào)),每次更新數(shù)據(jù)version+1,更新的時(shí)候?qū)姹咎?hào)作為條件進(jìn)行更新,根據(jù)更新影響的行數(shù)判斷更新是否成功,偽代碼如下:

1.查詢數(shù)據(jù),此時(shí)版本號(hào)為w_v
2.打開事務(wù)
3.做一些業(yè)務(wù)操作
4.update t set version = version+1 where id = 記錄id and version = w_v;//此行會(huì)返回影響的行數(shù)c
5.if(c>0){
        //提交事務(wù)
    }else{
        //回滾事務(wù)
    }

多個(gè)線程更新同一條數(shù)據(jù)的時(shí)候,數(shù)據(jù)庫會(huì)對(duì)當(dāng)前數(shù)據(jù)加鎖,同一時(shí)刻只有一個(gè)線程可以執(zhí)行更新語句。

無鎖(Lock-Free)

無鎖的并行都是無障礙的。在無鎖的情況下,所有的線程都能嘗試對(duì)臨界區(qū)進(jìn)行訪問,但不同的是,無鎖的并發(fā)保證必然有一個(gè)線程能夠在有限步內(nèi)完成操作離開臨界區(qū)。

在無鎖的調(diào)用中,一個(gè)典型的特點(diǎn)是可能會(huì)包含一個(gè)無窮循環(huán)。在這個(gè)循環(huán)中,線程會(huì)不斷嘗試修改共享變量。如果沒有沖突,修改成功,那么程序退出,否則繼續(xù)嘗試修改。但無論如何,無鎖的并行總能保證有一個(gè)線程是可以勝出的,不至于全軍覆沒。至于臨界區(qū)中競(jìng)爭(zhēng)失敗的線程,他們必須不斷重試,直到自己獲勝。如果運(yùn)氣很不好,總是嘗試不成功,則會(huì)出現(xiàn)類似饑餓的先寫,線程會(huì)停止。

下面就是一段無鎖的示意代碼,如果修改不成功,那么循環(huán)永遠(yuǎn)不會(huì)停止。

while(!atomicVar.compareAndSet(localVar, localVar+1)){
        localVal = atomicVar.get();
}

無等待

無鎖只要求有一個(gè)線程可以在有限步內(nèi)完成操作,而無等待則在無鎖的基礎(chǔ)上更進(jìn)一步擴(kuò)展。它要求所有線程都必須在有限步內(nèi)完成,這樣不會(huì)引起饑餓問題。如果限制這個(gè)步驟的上限,還可以進(jìn)一步分解為有界無等待和線程數(shù)無關(guān)的無等待等幾種,他們之間的區(qū)別只是對(duì)循環(huán)次數(shù)的限制不同。

一種典型的無等待結(jié)果就是RCU(Read Copy Update)。它的基本思想是,對(duì)數(shù)據(jù)的讀可以不加控制。因此,所有的讀線程都是無等待的,它們既不會(huì)被鎖定等待也不會(huì)引起任何沖突。但在寫數(shù)據(jù)的時(shí)候,先獲取原始數(shù)據(jù)的副本,接著只修改副本數(shù)據(jù)(這就是為什么讀可以不加控制),修改完成后,在合適的時(shí)機(jī)回寫數(shù)據(jù)。

java高并發(fā)系列連載中,總計(jì)估計(jì)會(huì)有四五十篇文章,可以關(guān)注公眾號(hào):javacode2018,獲取最新文章。

標(biāo)題名稱:java高并發(fā)系列-第2天:并發(fā)級(jí)別
文章源于:http://muchs.cn/article4/iepcoe.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站內(nèi)鏈、域名注冊(cè)品牌網(wǎng)站制作、關(guān)鍵詞優(yōu)化、網(wǎng)站設(shè)計(jì)公司、ChatGPT

廣告

聲明:本網(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í)需注明來源: 創(chuàng)新互聯(lián)

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