Java基礎(chǔ)-線程 (三)-鎖

CAS是什么?

了解CAS之前膨报,我們先了解變量的2大特性磷籍。

原子操作(原子性):對(duì)于操作A,要么執(zhí)行完现柠,要么完全不執(zhí)行院领。即一個(gè)操作或者多個(gè)操作要么全部執(zhí)行并且執(zhí)行的過(guò)程不會(huì)被任何因素打斷,要么就都不執(zhí)行够吩。

可見(jiàn)性:當(dāng)多個(gè)線程訪問(wèn)同一個(gè)變量時(shí)比然,一個(gè)線程修改了這個(gè)變量的值,其他線程能夠立即看得到修改的值周循。


CAS全名(Compare And Swap)强法,字面意思就是比較并且交換。實(shí)際操作也是如此的湾笛。

CAS是基于鎖的操作饮怯,并且它是樂(lè)觀鎖。CAS操作嚎研。通過(guò)不斷的自旋達(dá)到目的蓖墅,能夠在很短的時(shí)間持有和釋放資源。自旋操作嘉赎,可能會(huì)帶來(lái)cpu的性能過(guò)分消耗(自選始終達(dá)不到目的的時(shí)候置媳,這樣就會(huì)導(dǎo)致無(wú)限接近于死循環(huán))


我們常定義的根據(jù)獲取鎖的方式有2種

樂(lè)觀鎖:不加鎖的方式通過(guò)記錄比較的方式來(lái)進(jìn)行操作。通俗點(diǎn)說(shuō)就是公条,大家都可以操作拇囊,但是結(jié)果會(huì)根據(jù)沖突檢測(cè)結(jié)果而不同。因?yàn)槿绻l(fā)現(xiàn)沖突了靶橱,則返回給用戶錯(cuò)誤的信息寥袭,讓用戶決定如何去做路捧。樂(lè)觀鎖適用于讀操作多的場(chǎng)景,這樣可以提高程序的吞吐量传黄。(CAS就是樂(lè)觀鎖)(應(yīng)用于多讀場(chǎng)景)

悲觀鎖:?總是讓一個(gè)任務(wù)拿到鎖杰扫,執(zhí)行完畢釋放鎖過(guò)后其他任務(wù)才能接著拿鎖執(zhí)行。通俗點(diǎn)說(shuō)就是膘掰,大家只能一個(gè)個(gè)操作章姓,必須等前面一個(gè)拿到鎖釋放過(guò)后才能執(zhí)行下一個(gè)。synchronized?就是悲觀鎖识埋。(應(yīng)用于多寫場(chǎng)景)

我們常定義的根據(jù)獲取鎖時(shí)是否先參與排隊(duì)有2種

公平鎖:多個(gè)線程按照申請(qǐng)鎖的順序去獲得鎖凡伊,線程會(huì)直接進(jìn)入隊(duì)列去排隊(duì),永遠(yuǎn)都是隊(duì)列的第一位才能得到鎖窒舟。優(yōu)點(diǎn):所有的線程都能得到資源系忙,不會(huì)餓死在隊(duì)列中。缺點(diǎn):吞吐量會(huì)下降很多惠豺,隊(duì)列里面除了第一個(gè)線程银还,其他的線程都會(huì)阻塞,cpu喚醒阻塞線程的開(kāi)銷會(huì)很大洁墙。(如ReentrantLock蛹疯,可自定義設(shè)置公平或非公平)

非公平鎖:多個(gè)線程去獲取鎖的時(shí)候,會(huì)直接去嘗試獲取扫俺,獲取不到苍苞,再去進(jìn)入等待隊(duì)列,如果能獲取到狼纬,就直接獲取到鎖。優(yōu)點(diǎn):可以減少CPU喚醒線程的開(kāi)銷骂际,整體的吞吐效率會(huì)高點(diǎn)疗琉,CPU也不必取喚醒所有線程,會(huì)減少喚起線程的數(shù)量歉铝。缺點(diǎn):你們可能也發(fā)現(xiàn)了盈简,這樣可能導(dǎo)致隊(duì)列中間的線程一直獲取不到鎖或者長(zhǎng)時(shí)間獲取不到鎖,導(dǎo)致餓死太示。(如ReentrantLock柠贤,可自定義設(shè)置公平或非公平)

我們常定義的根據(jù)鎖的性質(zhì)分類有3種:

共享鎖:線程可以同時(shí)獲取鎖。ReentrantReadWriteLock對(duì)于讀鎖是共享的类缤。在讀多寫少的情況下使用共享鎖會(huì)非常高效臼勉。

重入鎖:線程獲取鎖后可以重復(fù)執(zhí)行鎖區(qū)域。Java提供的鎖都是可重入鎖餐弱。不可重入鎖非常容易導(dǎo)致死鎖宴霸。

排它鎖:多線程不可同時(shí)獲取的鎖囱晴,與共享鎖對(duì)立。與重入鎖不矛盾可以是并存屬性瓢谢。


我們常定義的根據(jù)狀態(tài)劃分有3種:

偏向鎖:一段同步代碼一直被一個(gè)線程所訪問(wèn)畸写,那么該線程會(huì)自動(dòng)獲取鎖。降低獲取鎖的代價(jià)氓扛。類似于樂(lè)觀鎖枯芬。

輕量級(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)入阻塞,性能降低础倍。


為什么說(shuō)CAS是樂(lè)觀鎖呢烛占,CAS上面提到,進(jìn)行的操作就是比較且進(jìn)行交換沟启。

每一個(gè)CAS操作過(guò)程都包含三個(gè)運(yùn)算符:一個(gè)內(nèi)存地址V忆家,一個(gè)期望的值A(chǔ)和一個(gè)新值B。在進(jìn)行一次CAS操作時(shí)德迹,如果這個(gè)地址上存放的值等于這個(gè)期望的值A(chǔ)芽卿,則將地址上的值賦為新值B,否則不做任何操作胳搞。這里看出CAS也是一個(gè)原子操作卸例。

由于CAS是一種樂(lè)觀鎖。那么在檢查沖突的時(shí)候肌毅,過(guò)分簡(jiǎn)單的條件會(huì)引起ABA問(wèn)題筷转。


什么是ABA問(wèn)題?

舉個(gè)栗子。

如果有2個(gè)線程:我們需要進(jìn)行如下操作悬而。A→B→A→C

線程1:在執(zhí)行的過(guò)程中把值從A→B→A呜舒。

線程2:在執(zhí)行的過(guò)程中,如果恰好線程1執(zhí)行完摊滔,線程A進(jìn)行檢測(cè)的時(shí)候以為A值未發(fā)生變化阴绢,把值又變成了B店乐。這樣就造成了操作錯(cuò)誤。

因?yàn)镃AS需要在操作值的時(shí)候呻袭,檢查值有沒(méi)有發(fā)生變化眨八,如果沒(méi)有發(fā)生變化則更新,但是如果一個(gè)值原來(lái)是A左电,變成了B廉侧,又變成了A,那么使用CAS進(jìn)行檢查時(shí)會(huì)發(fā)現(xiàn)它的值沒(méi)有發(fā)生變化篓足,但是實(shí)際過(guò)程中操作或者成員上卻發(fā)生了變化段誊。


如何解決ABA問(wèn)題,增加檢查沖突的條件栈拖。JDK5以上的atomic包里提供了解決辦法连舍。

Atomic包提供了以下3個(gè)類。

AtomicReference:原子更新引用類型涩哟。多個(gè)變量合并為一個(gè)變量索赏。類似一個(gè)類內(nèi)有多個(gè)變量。更改類內(nèi)的多個(gè)變量贴彼。然后通過(guò)比較類這個(gè)單一變量的CAS操作潜腻。

AtomicMarkableReference:原子更新帶有標(biāo)記位的引用類型。記錄改沒(méi)改過(guò)

AtomicStampedReference:版本戳的形式記錄了每次改變以后的版本號(hào)器仗。記錄該沒(méi)改過(guò)融涣,改過(guò)幾次。


CAS只能保證一個(gè)共享變量(因?yàn)橐粋€(gè)地址對(duì)應(yīng)一個(gè)變量)的原子操作精钮。當(dāng)代碼塊內(nèi)需要進(jìn)行多個(gè)變量更改操作時(shí)威鹿,CAS就不太適應(yīng)了。就需要使用其他鎖的機(jī)制操作轨香,如synchronized专普。

此外需要注意,CAS對(duì)cpu的開(kāi)銷可能會(huì)很大弹沽,因?yàn)樗且环N自旋操作。自旋操作可以無(wú)限接近于死循環(huán)筋粗。


Volatile:可以把對(duì)volatile變量的單個(gè)讀/寫策橘,看成是使用同一個(gè)鎖對(duì)這些單個(gè)讀/寫操作做了同步.一般是共享變量在多線程中的使用,讓每個(gè)線程能夠及時(shí)了解共享變量的變化娜亿。(只能保證可見(jiàn)性丽已,并不能保證原子性,詳見(jiàn)注意)买决,應(yīng)用場(chǎng)景:單線程寫沛婴,多線程讀吼畏。

注意:volatile對(duì)于變量讀/寫具有原子性具有原子性,但是類似于volatile++復(fù)合操作不具有原子性嘁灯,可能會(huì)導(dǎo)致多線程拿到的共享變量不一致泻蚊。


Synchronized:可用于修飾類、方法丑婿、代碼塊的同步鎖性雄,只有獲取鎖的線程能夠執(zhí)行,其他嘗試獲取鎖的線程均被阻塞羹奉。是重量級(jí)鎖秒旋。(可重入,依賴JVM實(shí)現(xiàn))(非公平鎖)(保證了可見(jiàn)性和原子性)诀拭,應(yīng)用場(chǎng)景:多線性讀寫迁筛。

sychronied修飾普通方法對(duì)象鎖,同一對(duì)象的對(duì)象鎖是干擾的耕挨,不同對(duì)象實(shí)例的對(duì)象鎖是互不干擾的

sychronied修飾靜態(tài)方法或類類鎖细卧,由于類只有一個(gè)(一個(gè)class對(duì)象),類鎖是互相干擾的俗孝。

可見(jiàn)性是指當(dāng)多個(gè)線程訪問(wèn)同一個(gè)變量時(shí),一個(gè)線程修改了這個(gè)變量的值赋铝,其他線程能夠立即看得到修改的值插勤。

ReentrantLock:可重入鎖,自己實(shí)現(xiàn)革骨。(可自定義設(shè)置公平或非公平)农尖。

PS:synchronized 是 JVM 實(shí)現(xiàn)的,而 ReentrantLock 是 JDK 實(shí)現(xiàn)的良哲。



上面有了解到根據(jù)鎖的狀態(tài)可以劃分為3種盛卡,這里加上無(wú)鎖狀態(tài)的也可以稱鎖有四種狀態(tài):無(wú)鎖狀態(tài),偏向鎖狀態(tài)筑凫,輕量級(jí)鎖狀態(tài)和重量級(jí)鎖狀態(tài)滑沧,它會(huì)隨著競(jìng)爭(zhēng)情況逐漸升級(jí)。鎖可以升級(jí)但不能降級(jí)巍实,目的是為了提高獲得鎖和釋放鎖的效率滓技。

鎖的狀態(tài)是存放在對(duì)象頭中的。對(duì)象頭的狀態(tài)可能隨著對(duì)象在運(yùn)行過(guò)重發(fā)生改變棚潦。即鎖的狀態(tài)可能會(huì)發(fā)生變化令漂。所以引入了鎖的這4種狀態(tài)。


鎖狀態(tài):?無(wú)鎖、偏向鎖叠必、輕量級(jí)鎖荚孵、重量級(jí)鎖。

無(wú)鎖:不鎖住資源纬朝,多個(gè)線程只有一個(gè)能修改資源成功旭等,其他線程會(huì)重試损敷。

偏向鎖:它會(huì)偏向于第一個(gè)訪問(wèn)鎖的線程,如果在運(yùn)行過(guò)程中,同步鎖只有一個(gè)線程訪問(wèn)玷犹,不存在多線程爭(zhēng)用的情況粱锐,則線程是不需要觸發(fā)同步的篮洁,這種情況下邑商,就會(huì)給線程加一個(gè)偏向鎖。單線程場(chǎng)景患膛。(應(yīng)用場(chǎng)景:幾乎無(wú)競(jìng)爭(zhēng)的情況下摊阀。)ps:同一線程執(zhí)行同步資源時(shí)自動(dòng)獲取。

偏向鎖→輕量級(jí)鎖:在大多數(shù)情況下一個(gè)鎖是同一線程使用的踪蹬,在線程拿鎖的過(guò)程中不進(jìn)行CAS操作只簡(jiǎn)單檢查上個(gè)拿鎖線程是否是自己(因?yàn)槠蜴i對(duì)象頭有線程ID)胞此,直接給偏向鎖線程。

輕量級(jí)鎖:輕量級(jí)鎖是由偏向所升級(jí)來(lái)的跃捣,偏向鎖運(yùn)行在一個(gè)線程進(jìn)入同步塊的情況下漱牵,當(dāng)?shù)诙€(gè)線程加入鎖爭(zhēng)用的時(shí)候,偏向鎖就會(huì)升級(jí)為輕量級(jí)鎖疚漆。(應(yīng)用場(chǎng)景:輕度競(jìng)爭(zhēng)的情況下酣胀。比如臨界訪問(wèn)。?ps:多線程爭(zhēng)奪同步資源時(shí)娶聘,沒(méi)拿到鎖的線程自旋等待資源鎖釋放闻镶。

輕量級(jí)→重量級(jí):假如前一個(gè)拿鎖的線程運(yùn)行很快,后一個(gè)輕量級(jí)鎖線程就使用CAS操作自旋操作幾次丸升,拿到鎖即成功铆农,否則鎖撤銷并升級(jí)為重量級(jí)鎖。(可看出有鎖撤銷的額外操作狡耻,一般使用輕量級(jí)鎖最多墩剖。)

重量級(jí)鎖:僅持有鎖的對(duì)象能夠運(yùn)行,其他競(jìng)爭(zhēng)對(duì)象均阻塞夷狰。(應(yīng)用場(chǎng)景:多線程競(jìng)爭(zhēng)激烈涛碑。)ps:多線程競(jìng)爭(zhēng)同步資源時(shí),沒(méi)拿到鎖的線程阻塞等待被喚醒孵淘。

synchronized鎖優(yōu)化引用了這些狀態(tài)變化。優(yōu)化性能(因?yàn)樯舷挛那袚Q性能損耗遠(yuǎn)大于運(yùn)算歹篓,鎖優(yōu)化的核心思想就是盡量避免上下文切換進(jìn)行操作)瘫证。synchronized是JVM層次實(shí)現(xiàn)的揉阎,已做過(guò)大量?jī)?yōu)化,官方推薦的形式背捌。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末毙籽,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子毡庆,更是在濱河造成了極大的恐慌坑赡,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件么抗,死亡現(xiàn)場(chǎng)離奇詭異毅否,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)蝇刀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門螟加,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人吞琐,你說(shuō)我怎么就攤上這事捆探。” “怎么了站粟?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵黍图,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我奴烙,道長(zhǎng)助被,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任缸沃,我火速辦了婚禮恰起,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘趾牧。我一直安慰自己检盼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布翘单。 她就那樣靜靜地躺著吨枉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪哄芜。 梳的紋絲不亂的頭發(fā)上貌亭,一...
    開(kāi)封第一講書(shū)人閱讀 51,698評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音认臊,去河邊找鬼圃庭。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的剧腻。 我是一名探鬼主播拘央,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼书在!你這毒婦竟也來(lái)了灰伟?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤儒旬,失蹤者是張志新(化名)和其女友劉穎栏账,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體栈源,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡挡爵,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了凉翻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片了讨。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖制轰,靈堂內(nèi)的尸體忽然破棺而出前计,到底是詐尸還是另有隱情,我是刑警寧澤垃杖,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布男杈,位于F島的核電站,受9級(jí)特大地震影響调俘,放射性物質(zhì)發(fā)生泄漏伶棒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一彩库、第九天 我趴在偏房一處隱蔽的房頂上張望肤无。 院中可真熱鬧,春花似錦骇钦、人聲如沸宛渐。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)窥翩。三九已至,卻和暖如春鳞仙,著一層夾襖步出監(jiān)牢的瞬間寇蚊,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工棍好, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留仗岸,地道東北人允耿。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像爹梁,于是被迫代替她去往敵國(guó)和親右犹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容