26.StampedLock

1.簡(jiǎn)介

ReentrantReadWriteLock采用的是“悲觀讀”的策略孵奶,當(dāng)?shù)谝粋€(gè)讀線程拿到鎖之后,第二個(gè)、第三個(gè)讀線程還可以拿到鎖翘魄,使得寫線程一直拿不到鎖,可能導(dǎo)致寫線程“餓死”舀奶。雖然在其公平或非公平的實(shí)現(xiàn)中暑竟,都盡量避免這種情形(寫鎖偏向性,優(yōu)先級(jí)高)育勺,但還有可能發(fā)生光羞。

StampedLock引入了“樂(lè)觀讀”策略绩鸣,讀的時(shí)候不加讀鎖,讀出來(lái)發(fā)現(xiàn)數(shù)據(jù)被修改了纱兑,再升級(jí)為“悲觀讀”呀闻,相當(dāng)于降低了“讀”的地位,把搶鎖的天平往“寫”的一方傾斜了一下潜慎,避免寫線程被餓死捡多。

2.使用場(chǎng)景

class Point { 
    private double x, y; 
    private final StampedLock sl = new StampedLock(); 
    // 多個(gè)線程調(diào)用該方法,修改x和y的值 
    void move(double deltaX, double deltaY) { 
        long stamp = sl.writeLock(); 
        try {
            x += deltaX; y += deltaY; 
        } finally { 
            sl.unlockWrite(stamp); 
        } }
    // 多個(gè)線程調(diào)用該方法铐炫,求距離 
    double distenceFromOrigin() {
        // 使用“樂(lè)觀讀” 
        long stamp = sl.tryOptimisticRead(); 
        // 將共享變量拷貝到線程棧 
        double currentX = x, currentY = y; 
        // 讀期間有其他線程修改數(shù)據(jù)
        if (!sl.validate(stamp)) { 
            // 讀到的是臟數(shù)據(jù)垒手,丟棄。 
            // 重新使用“悲觀讀” 
            stamp = sl.readLock(); 
            try {
                currentX = x; currentY = y; 
            } finally { sl.unlockRead(stamp); 
        } }
        return Math.sqrt(currentX * currentX + currentY * currentY); 
    } }

有一個(gè)Point類倒信,多個(gè)線程調(diào)用move()方法科贬,修改坐標(biāo);還有多個(gè)線程調(diào)用distanceFromOrigin()方法鳖悠,求距離榜掌。
首先,執(zhí)行move操作的時(shí)候乘综,要加寫鎖憎账。這個(gè)用法和ReadWriteLock的用法沒(méi)有區(qū)別,寫操作和寫操作也是互斥的卡辰。
關(guān)鍵在于讀的時(shí)候胞皱,用了一個(gè)“樂(lè)觀讀”sl.tryOptimisticRead(),相當(dāng)于在讀之前給數(shù)據(jù)的狀態(tài)做了一個(gè)“快照”九妈。然后反砌,把數(shù)據(jù)拷貝到內(nèi)存里面,在用之前萌朱,再比對(duì)一次版本號(hào)于颖。如果版本號(hào)變了,則說(shuō)明在讀的期間有其他線程修改了數(shù)據(jù)嚷兔。讀出來(lái)的數(shù)據(jù)廢棄,重新獲取讀鎖做入。


要說(shuō)明的是冒晰,這三行關(guān)鍵代碼對(duì)順序非常敏感,不能有重排序竟块。因?yàn)?state 變量已經(jīng)是volatile壶运,所以可以禁止重排序,但stamp并不是volatile的浪秘。為此蒋情,在validate(stamp)方法里面插入內(nèi)存屏障埠况。

public boolean validate(long stamp) { 
    VarHandle.acquireFence();   //內(nèi)存屏障
    return (stamp & SBITS) == (state & SBITS); 
}

3. “樂(lè)觀讀”的實(shí)現(xiàn)原理

首先,StampedLock是一個(gè)讀寫鎖棵癣,因此也會(huì)像讀寫鎖那樣辕翰,把一個(gè)state變量分成兩半,分別表示讀鎖和寫鎖的狀態(tài)狈谊。同時(shí)喜命,它還需要一個(gè)數(shù)據(jù)的version。但是河劝,一次CAS沒(méi)有辦法操作兩個(gè)變量壁榕,所以這個(gè)state變量本身同時(shí)也表示了數(shù)據(jù)的version。



用最低的8位表示讀和寫的狀態(tài)赎瞎,其中第8位表示寫鎖的狀態(tài)牌里,最低的7位表示讀鎖的狀態(tài)。因?yàn)閷戞i只有一個(gè)bit位务甥,所以寫鎖是不可重入的牡辽。

4 悲觀讀/寫:“阻塞”與“自旋”策略實(shí)現(xiàn)差異

StampedLock也要進(jìn)行悲觀的讀鎖和寫鎖操作。不過(guò)缓呛,它不是基于AQS實(shí)現(xiàn)的催享,而是內(nèi)部重新實(shí)現(xiàn)了一個(gè)阻塞隊(duì)列。

  • 剛開(kāi)始的時(shí)候哟绊,whead=wtail=NULL因妙,然后初始化,建一個(gè)空節(jié)點(diǎn)票髓,whead和wtail都指向這個(gè)空節(jié)點(diǎn)攀涵,之后往里面加入一個(gè)個(gè)讀線程或?qū)懢€程節(jié)點(diǎn)。
  • 基于這個(gè)阻塞隊(duì)列實(shí)現(xiàn)的鎖的調(diào)度策略和AQS很不一樣洽沟,也就是“自旋”以故。
  • 不同點(diǎn):在AQS里面,當(dāng)一個(gè)線程CAS state失敗之后裆操,會(huì)立即加入阻塞隊(duì)列怒详,并且進(jìn)入阻塞狀態(tài)。
  • 但在StampedLock中踪区,CAS state失敗之后昆烁,會(huì)不斷自旋,自旋足夠多的次數(shù)之后缎岗,如果還拿不到鎖静尼,才進(jìn)入阻塞狀態(tài)。
    根據(jù)CPU的核數(shù),定義了自旋次數(shù)的常量值

StampedLock還提供了更復(fù)雜的將悲觀讀鎖升級(jí)為寫鎖的功能鼠渺,它主要使用在if-then-update的場(chǎng)景:即先讀鸭巴,如果讀的數(shù)據(jù)滿足條件,就返回拦盹,如果讀的數(shù)據(jù)不滿足條件鹃祖,再嘗試寫。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末掌敬,一起剝皮案震驚了整個(gè)濱河市惯豆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌奔害,老刑警劉巖楷兽,帶你破解...
    沈念sama閱讀 211,376評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異华临,居然都是意外死亡芯杀,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門雅潭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)揭厚,“玉大人,你說(shuō)我怎么就攤上這事扶供∩冈玻” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 156,966評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵椿浓,是天一觀的道長(zhǎng)太援。 經(jīng)常有香客問(wèn)我,道長(zhǎng)扳碍,這世上最難降的妖魔是什么提岔? 我笑而不...
    開(kāi)封第一講書人閱讀 56,432評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮笋敞,結(jié)果婚禮上碱蒙,老公的妹妹穿的比我還像新娘。我一直安慰自己夯巷,他們只是感情好赛惩,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著趁餐,像睡著了一般喷兼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上澎怒,一...
    開(kāi)封第一講書人閱讀 49,792評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼喷面。 笑死星瘾,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的惧辈。 我是一名探鬼主播琳状,決...
    沈念sama閱讀 38,933評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼盒齿!你這毒婦竟也來(lái)了念逞?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,701評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤边翁,失蹤者是張志新(化名)和其女友劉穎翎承,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體符匾,經(jīng)...
    沈念sama閱讀 44,143評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡叨咖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了啊胶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片甸各。...
    茶點(diǎn)故事閱讀 38,626評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖焰坪,靈堂內(nèi)的尸體忽然破棺而出趣倾,到底是詐尸還是另有隱情,我是刑警寧澤某饰,帶...
    沈念sama閱讀 34,292評(píng)論 4 329
  • 正文 年R本政府宣布儒恋,位于F島的核電站,受9級(jí)特大地震影響露乏,放射性物質(zhì)發(fā)生泄漏碧浊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評(píng)論 3 313
  • 文/蒙蒙 一瘟仿、第九天 我趴在偏房一處隱蔽的房頂上張望箱锐。 院中可真熱鬧,春花似錦劳较、人聲如沸驹止。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)臊恋。三九已至,卻和暖如春墓捻,著一層夾襖步出監(jiān)牢的瞬間抖仅,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留撤卢,地道東北人环凿。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像放吩,于是被迫代替她去往敵國(guó)和親智听。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評(píng)論 2 348

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

  • ![Flask](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAW...
    極客學(xué)院Wiki閱讀 7,240評(píng)論 0 3
  • 不知不覺(jué)易趣客已經(jīng)在路上走了快一年了,感覺(jué)也該讓更多朋友認(rèn)識(shí)知道易趣客惕澎,所以就謝了這篇簡(jiǎn)介莉测,已做創(chuàng)業(yè)記事。 易趣客...
    Physher閱讀 3,410評(píng)論 1 2
  • 雙胎妊娠有家族遺傳傾向集灌,隨母系遺傳悔雹。有研究表明,如果孕婦本人是雙胎之一欣喧,她生雙胎的機(jī)率為1/58腌零;若孕婦的父親或母...
    鄴水芙蓉hibiscus閱讀 3,696評(píng)論 0 2
  • 晴天益涧,擁抱陽(yáng)光,擁抱你驯鳖。雨天闲询,想念雨滴,想念你浅辙。 我可以喜歡你嗎可以啊 我還可以喜歡你嗎可以扭弧,可是你要知道我們不可...
    露薇霜凝閱讀 1,208評(píng)論 1 2