樂觀鎖與悲觀鎖

何謂悲觀鎖與樂觀鎖

樂觀鎖對應(yīng)于生活中樂觀的人總是想著事情往好的方向發(fā)展,悲觀鎖對應(yīng)于生活中悲觀的人總是想著事情往壞的方向發(fā)展转质。這兩種人各有優(yōu)缺點届巩,不能不以場景而定說一種人好于另外一種人。

悲觀鎖

總是假設(shè)最壞的情況,每次去拿數(shù)據(jù)的時候都認為別人會修改丧失,所以每次在拿數(shù)據(jù)的時候都會上鎖,這樣別人想拿這個數(shù)據(jù)就會阻塞直到它拿到鎖(共享資源每次只給一個線程使用惜互,其它線程阻塞布讹,用完后再把資源轉(zhuǎn)讓給其它線程)琳拭。傳統(tǒng)的關(guān)系型數(shù)據(jù)庫里邊就用到了很多這種鎖機制,比如行鎖描验,表鎖等白嘁,讀鎖,寫鎖等膘流,都是在做操作之前先上鎖絮缅。Java 中 synchronized 和ReentrantLock 等獨占鎖就是悲觀鎖思想的實現(xiàn)。

樂觀鎖

總是假設(shè)最好的情況呼股,每次去拿數(shù)據(jù)的時候都認為別人不會修改耕魄,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數(shù)據(jù)卖怜,可以使用版本號機制和 CAS 算法實現(xiàn)屎开。樂觀鎖適用于多讀的應(yīng)用類型,這樣可以提高吞吐量马靠,像數(shù)據(jù)庫提供的類似于 write_condition 機制奄抽,其實都是提供的樂
觀鎖。在 Java 中 java.util.concurrent.atomic 包下面的原子變量類就是使用了樂觀鎖的一種實現(xiàn)方式 CAS 實現(xiàn)的甩鳄。

兩種鎖的使用場景

從上面對兩種鎖的介紹逞度,我們知道兩種鎖各有優(yōu)缺點,不可認為一種好于另一種妙啃,像樂觀鎖適用于寫比較少的情況下(多讀場景)档泽,即沖突真的很少發(fā)生的時候,這樣可以省去了鎖的開銷揖赴,加大了系統(tǒng)的整個吞吐量馆匿。但如果是多寫的情況,一般會經(jīng)常產(chǎn)生沖突燥滑,這就會導(dǎo)致上層應(yīng)用會不斷的進行 retry渐北,這樣反倒是降低了性能,所以一般多寫的場景下用悲觀鎖就比較合適铭拧。

樂觀鎖常見的兩種實現(xiàn)方式

樂觀鎖一般會使用版本號機制或 CAS 算法實現(xiàn)赃蛛。

1. 版本號機制

一般是在數(shù)據(jù)表中加上一個數(shù)據(jù)版本號 version 字段,表示數(shù)據(jù)被修改的次數(shù)搀菩,當(dāng)數(shù)據(jù)被修改時呕臂,version 值會加一。當(dāng)線程 A 要更新數(shù)據(jù)值時肪跋,在讀取數(shù)據(jù)的同時也會讀取 version 值歧蒋,在提交更新時,若剛才讀取到的 version 值為當(dāng)前數(shù)據(jù)庫中的 version 值相等時才更新,否則重試更新操作疏尿,直到更新成功瘟芝。
舉一個簡單的例子: 假設(shè)數(shù)據(jù)庫中帳戶信息表中有一個 version 字段,當(dāng)前值為 1 褥琐;而當(dāng)前帳戶余額字段( balance )為 $100 锌俱。

  1. 操作員 A 此時將其讀出( version=1 ),并從其帳戶余額中扣除 50(100-$50 )敌呈。
  2. 在操作員 A 操作的過程中贸宏,操作員 B 也讀入此用戶信息(
    version=1 ),并從其帳戶余額中扣除 20 (100-$20 )磕洪。
  3. 操作員 A 完成了修改工作吭练,將數(shù)據(jù)版本號加一( version=2 ),連同帳戶扣除后余額( balance=$50 )析显,提交至數(shù)據(jù)庫更新鲫咽,此時由于提交數(shù)據(jù)版本大于數(shù)據(jù)庫記錄當(dāng)前版本,數(shù)據(jù)被更新谷异,數(shù)據(jù)庫記錄version 更新為 2 分尸。
  4. 操作員 B 完成了操作,也將版本號加一( version=2 )試圖向數(shù)據(jù)庫提交數(shù)據(jù)( balance=$80 )歹嘹,但此時比對數(shù)據(jù)庫記錄版本時發(fā)現(xiàn)箩绍,操作員 B 提交的數(shù)據(jù)版本號為 2 ,數(shù)據(jù)庫記錄當(dāng)前版本也為 2 尺上,不滿足 “ 提交版本必須大于記錄當(dāng)前版本才能執(zhí)行更新 “ 的樂觀鎖策略材蛛,因此,操作員 B 的提交被駁回怎抛。
    這樣卑吭,就避免了操作員 B 用基于 version=1 的舊數(shù)據(jù)修改的結(jié)果覆蓋操作員A 的操作結(jié)果的可能。
2. CAS 算法

即 compare and swap(比較與交換)马绝,是一種有名的無鎖算法陨簇。無鎖編程,即不使用鎖的情況下實現(xiàn)多線程之間的變量同步迹淌,也就是在沒有線程被阻塞的情況下實現(xiàn)變量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)己单。CAS 算法涉及到三個操作數(shù)

  • 需要讀寫的內(nèi)存值 V
  • 進行比較的值 A
  • 擬寫入的新值 B
    當(dāng)且僅當(dāng) V 的值等于 A 時唉窃,CAS 通過原子方式用新值 B 來更新 V 的值,否則不會執(zhí)行任何操作(比較和替換是一個原子操作)纹笼。一般情況下是一個自旋操作纹份,即不斷的重試。
    關(guān)于自旋鎖,大家可以看一下這篇文章蔓涧,非常不錯:《 面試必備之深入理解自旋鎖》

樂觀鎖的缺點

ABA 問題是樂觀鎖一個常見的問題

1 ABA 問題

如果一個變量 V 初次讀取的時候是 A 值件已,并且在準備賦值的時候檢查到它仍然是 A 值,那我們就能說明它的值沒有被其他線程修改過了嗎元暴?很明顯是不能的篷扩,因為在這段時間它的值可能被改為其他值,然后又改回 A茉盏,那 CAS 操作就會誤認為它從來沒有被修改過鉴未。這個問題被稱為 CAS 操作的 "ABA"問題。
JDK 1.5 以后的 AtomicStampedReference 類就提供了此種能力鸠姨,其中的compareAndSet 方法就是首先檢查當(dāng)前引用是否等于預(yù)期引用铜秆,并且當(dāng)前標志是否等于預(yù)期標志,如果全部相等讶迁,則以原子方式將該引用和該標志的值設(shè)置為給定的更新值连茧。

2 循環(huán)時間長開銷大

自旋 CAS(也就是不成功就一直循環(huán)執(zhí)行直到成功)如果長時間不成功,會給CPU 帶來非常大的執(zhí)行開銷巍糯。 如果 JVM 能支持處理器提供的 pause 指令那么效率會有一定的提升啸驯,pause 指令有兩個作用,第一它可以延遲流水線執(zhí)行指令(de-pipeline),使 CPU 不會消耗過多的執(zhí)行資源鳞贷,延遲的時間取決于具體實現(xiàn)的版本坯汤,在一些處理器上延遲時間是零。第二它可以避免在退出循環(huán)的時候因內(nèi)存順序沖突(memory order violation)而引起 CPU 流水線被清空(CPU pipeline flush)搀愧,從而提高 CPU 的執(zhí)行效率惰聂。

3 只能保證一個共享變量的原子操作

CAS 只對單個共享變量有效,當(dāng)操作涉及跨多個共享變量時 CAS 無效咱筛。但是從 JDK 1.5 開始搓幌,提供了 AtomicReference 類來保證引用對象之間的原子性溉愁,你可以把多個變量放在一個對象里來進行 CAS 操作.所以我們可以使用鎖或者利用AtomicReference 類把多個共享變量合并成一個共享變量來操作。

CAS 與 synchronized 的使用情景

簡單的來說 CAS 適用于寫比較少的情況下(多讀場景,沖突一般較少)讨衣,
synchronized 適用于寫比較多的情況下(多寫場景,沖突一般較多)

  1. 對于資源競爭較少(線程沖突較輕)的情況歹茶,使用 synchronized 同步鎖
    進行線程阻塞和喚醒切換以及用戶態(tài)內(nèi)核態(tài)間的切換操作額外浪費消耗cpu 資源;而 CAS 基于硬件實現(xiàn),不需要進入內(nèi)核,不需要切換線程,操作自旋幾率較少磁浇,因此可以獲得更高的性能缔赠。
  2. 對于資源競爭嚴重(線程沖突嚴重)的情況,CAS 自旋的概率會比較大告匠,從而浪費更多的 CPU 資源男娄,效率低于 synchronized。

補充: Java 并發(fā)編程這個領(lǐng)域中 synchronized 關(guān)鍵字一直都是元老級的角色,很久之前很多人都會稱它為 “重量級鎖” 实夹。但是橄浓,在 JavaSE 1.6 之后進行了主要包括為了減少獲得鎖和釋放鎖帶來的性能消耗而引入的 偏向鎖 和 輕量級鎖 以及其它各種優(yōu)化之后變得在某些情況下并不是那么重了。synchronized 的底層實現(xiàn)主要依靠 Lock-Free 的隊列亮航,基本思路是 自旋后阻塞荸实,競爭切換后繼續(xù)競爭鎖,稍微犧牲了公平性缴淋,但獲得了高吞吐量准给。在線程沖突較少的情況下,可以獲得和 CAS 類似的性能重抖;而線程沖突嚴重的情況下露氮,性能遠高于CAS。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末钟沛,一起剝皮案震驚了整個濱河市畔规,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌恨统,老刑警劉巖叁扫,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異延欠,居然都是意外死亡陌兑,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門由捎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來兔综,“玉大人,你說我怎么就攤上這事狞玛∪沓郏” “怎么了?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵心肪,是天一觀的道長锭亏。 經(jīng)常有香客問我,道長硬鞍,這世上最難降的妖魔是什么慧瘤? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任戴已,我火速辦了婚禮,結(jié)果婚禮上锅减,老公的妹妹穿的比我還像新娘糖儡。我一直安慰自己,他們只是感情好怔匣,可當(dāng)我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布握联。 她就那樣靜靜地躺著,像睡著了一般每瞒。 火紅的嫁衣襯著肌膚如雪金闽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天剿骨,我揣著相機與錄音代芜,去河邊找鬼。 笑死懦砂,一個胖子當(dāng)著我的面吹牛蜒犯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播荞膘,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼罚随,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了羽资?” 一聲冷哼從身側(cè)響起淘菩,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎屠升,沒想到半個月后潮改,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡腹暖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年汇在,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片脏答。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡糕殉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出殖告,到底是詐尸還是另有隱情阿蝶,我是刑警寧澤,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布黄绩,位于F島的核電站羡洁,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏爽丹。R本人自食惡果不足惜筑煮,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一辛蚊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧咆瘟,春花似錦嚼隘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谤狡。三九已至灸眼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間墓懂,已是汗流浹背焰宣。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留捕仔,地道東北人匕积。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像榜跌,于是被迫代替她去往敵國和親闪唆。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,689評論 2 354

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

  • 首先介紹一些樂觀鎖與悲觀鎖: 悲觀鎖:總是假設(shè)最壞的情況钓葫,每次去拿數(shù)據(jù)的時候都認為別人會修改悄蕾,所以每次在拿數(shù)據(jù)的時...
    奧莉安娜的棒棒糖閱讀 1,584評論 0 19
  • 何謂悲觀鎖與樂觀鎖 樂觀鎖對應(yīng)于生活中樂觀的人總是想著事情往好的方向發(fā)展,悲觀鎖對應(yīng)于生活中悲觀的人總是想著事情往...
    valor_wang閱讀 319評論 0 1
  • 一础浮、何謂悲觀鎖與樂觀鎖 樂觀鎖對應(yīng)于生活中樂觀的人總是想著事情往好的方向發(fā)展帆调,悲觀鎖對應(yīng)于生活中悲觀的人總是想著事...
    愛情小傻蛋閱讀 400評論 0 0
  • 18年后三月份在廣州找頂崗實習(xí)的工作,意向工作是花藝師豆同,或者是跟花藝相關(guān)的番刊,前后面試了好幾份:獵文化花藝培訓(xùn)店店員...
    吃喝玩樂2019閱讀 746評論 0 0
  • 篩法——求n以內(nèi)質(zhì)數(shù)個數(shù) int prime[Max]; bool flag[Max]; int EulerSie...
    ThWh閱讀 124評論 0 0