CAS與AQS簡單理解

什么是CAS

所謂的CAS既是compareAndSwap的縮寫恋技,翻譯過來既是“對比和交換”的意思雄人。

那怎么去對比呢妈倔,畫個小圖理解下:

image-20220531192924878.png

3個值分別對應(yīng)的含義:

  • 新的值:需要修改過后的值

  • 內(nèi)存變量的值:在內(nèi)存的值是多少

  • 舊的預(yù)期值:這里相當(dāng)于內(nèi)存的值的一個副本,copy過來的

    如果內(nèi)存的值等于舊的預(yù)期值里烦,那么就把新的值替換為內(nèi)存中的值损离,否則什么都不做

    這里就是自旋鎖

AtomicInteger就是用到CAS來實(shí)現(xiàn)的哥艇。 用代碼理解下:

// 類似上述全局內(nèi)存共享變量V
AtomicInteger atomicInteger = new AtomicInteger(0);
// CAS操作
boolean b = atomicInteger.compareAndSet(0, 1);
System.out.println("是否修改成功:" + b);
System.out.println("修改后的值:"+ atomicInteger.get());

打印:

是否修改成功:true 修改后的值:1

那么此時(shí)有多個線程同時(shí)請求如下:

image-20220531202608921.png

線程T1草冈,T2同時(shí)需要修改內(nèi)存中的變量值“加1”操作流程如下

  • 此時(shí)線程T1她奥,T2內(nèi)存中的值都為0

  • T1:此時(shí)V=0,E=0,發(fā)現(xiàn)V=E怎棱,那么把V修改為N哩俭,那么現(xiàn)在V=1

  • T2:此時(shí)V=1,E=0,發(fā)下V!=E拳恋,那么重新讀取(自旋)內(nèi)存中的值把E的值改成1凡资,這時(shí)V=E了。

ABA問題

什么是ABA問題。 假設(shè)變量0被線程B修改成了2隙赁,再被自己或者其他線程又修改成了0垦藏,那么對于線程A來說,并沒有感知到伞访。因?yàn)榫€程A對比了0和0還是相等的掂骏。這就是ABA問題。那么如何解決呢厚掷?

加版本號處理弟灼。怎么處理?

也就是不管哪個線程修改了變量值冒黑,都把版本號加一田绑。那么其他線程讀取的時(shí)候就感知到了。原來被修改過

底層其實(shí)是通過C去實(shí)現(xiàn)的

C語言指令:

lock cmpxchg 

什么是AQS

所謂的AQS既是AbstractQueuedSynchronizer的縮寫

AbstractQueuedSynchronizer(AQS)是JDK中實(shí)現(xiàn)并發(fā)編程的核心抡爹,平時(shí)我們工作中經(jīng)常用到的ReentrantLock掩驱,CountDownLatch等都是基于它來實(shí)現(xiàn)的。

以ReentrantLock為例:

ReentrantLock reentrantLock = new ReentrantLock();
reentrantLock.lock();

底層源碼其實(shí)是通過Sync這個來實(shí)現(xiàn)的:

public void lock() {
 sync.lock();
}

再點(diǎn)進(jìn)去發(fā)現(xiàn)冬竟,其實(shí)就是AbstractQueuedSynchronizer的子類

abstract static class Sync extends AbstractQueuedSynchronizer {
 private static final long serialVersionUID = -5179523762034025860L;

 /**
 * Performs {@link Lock#lock}. The main reason for subclassing
 * is to allow fast path for nonfair version.
 */
 abstract void lock();
 ...
}

此時(shí)發(fā)現(xiàn)lock抽象方法的實(shí)現(xiàn)有兩個

image-20220531205123010.png

分別是FairSync(公平鎖)和NonfairSync(非公平鎖)均屬于ReentrantLock內(nèi)部類

那么怎么決定使用公平鎖或非公平鎖呢,可以通過ReentrantLock的構(gòu)造函數(shù)欧穴,默認(rèn)是用非公平鎖。

public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}

公平鎖非公平鎖

  • 公平鎖:所謂的公平鎖呢會按照嚴(yán)格的執(zhí)行順序來分配的泵殴。

  • 非公平鎖:競爭鎖的線程允許來插隊(duì)來搶占鎖的資源苔可。

畫個小圖理解下:

公平鎖

image-20220531210850794.png

此時(shí)有4個線程分別是T1,T2,T3,T4,同時(shí)調(diào)用這個方法。那么必然只會有一個線程會拿到鎖袋狞。

假設(shè)此時(shí)T1線程拿到了鎖,那么其他T2,T3,T4會阻塞映屋。那么作為公平鎖怎么處理呢苟鸯,讓其實(shí)現(xiàn)一個公平狀態(tài)

可以使其T2,T3,T4放入一個鏈表中等待,那么T1釋放的鎖棚点,這個時(shí)候呢T1不會喚醒T2,T3,T4早处,只會喚醒(LockSupport.unpark)T2,交給T2持有鎖瘫析,

那么T1呢砌梆,加入鏈表后續(xù)等待。就變成了這樣贬循。

image-20220531211209012.png

那什么是非公平的呢咸包?非公平其實(shí)就是通過cpu去爭搶,在多線程的場景下如果哪個線程搶到了鎖杖虾,那么就會持有這把鎖烂瘫。

有的時(shí)候就會發(fā)現(xiàn)多線程的場景下會有相同的線程去執(zhí)行。而并非上述的T1,T2,T3,T4按照順序去執(zhí)行奇适。

image-20220601194510122.png

非公平鎖:

首先T1,T2,T3,來CAS搶占鎖坟比,假設(shè)此時(shí)T1搶占成功了芦鳍,那么這時(shí)T2,T3會阻塞,怎么阻塞呢葛账,他們會加入到一個鏈表中等待柠衅,

注意:這是一個雙向鏈表,且有頭有尾籍琳。首節(jié)點(diǎn)是獲取到鎖的節(jié)點(diǎn)菲宴,其他的都是阻塞的節(jié)點(diǎn)

這時(shí)我們在總結(jié)寫公平鎖與非公平鎖的優(yōu)缺點(diǎn)

  • 優(yōu)點(diǎn):所有的線程都能得到資源,不會餓死在隊(duì)列中巩割。

  • 缺點(diǎn):吞吐量會下降很多裙顽,隊(duì)列里面除了第一個線程,其他的線程都會阻塞宣谈,cpu喚醒阻塞線程的開銷會很大愈犹。

非公平鎖:多個線程去獲取鎖的時(shí)候,會直接去嘗試獲取闻丑,獲取不到漩怎,再去進(jìn)入等待隊(duì)列,如果能獲取到嗦嗡,就直接獲取到鎖勋锤。

  • 優(yōu)點(diǎn):可以減少CPU喚醒線程的開銷,整體的吞吐效率會高點(diǎn)侥祭,CPU也不必取喚醒所有線程叁执,會減少喚起線程的數(shù)量。

  • 缺點(diǎn):你們可能也發(fā)現(xiàn)了矮冬,這樣可能導(dǎo)致隊(duì)列中間的線程一直獲取不到鎖或者長時(shí)間獲取不到鎖谈宛,導(dǎo)致餓死。

非公平鎖的設(shè)計(jì)理念

其實(shí)像ReentrantLock還是像synchronized等都是一樣胎署,默認(rèn)都是非公平鎖的策略吆录,之所以這么設(shè)計(jì),是考慮到性能這方面的原因琼牧,

因?yàn)槿绻凑展芥i的策略去進(jìn)行阻塞等待恢筝,同時(shí)AQS又喚醒正在等待的線程,這里會涉及到一個內(nèi)核態(tài)的切換巨坊,對性能會有一定的影響撬槽。如果是非公平鎖呢,當(dāng)前線程正好在上一個線程釋放的臨界點(diǎn)去搶占到了鎖這意味著這個線程不會進(jìn)行內(nèi)核態(tài)的切換

AQS雙向鏈表的作用?
1.線程中斷 需要刪除當(dāng)前線程被封裝的Node節(jié)點(diǎn) 這是就變成了鏈表的刪除操作
如果想從CLH 單向鏈表中間刪除一個 Node趾撵,因?yàn)橹痪S護(hù)了前一個節(jié)點(diǎn)的指針恢氯,想要知道后一個節(jié)點(diǎn)的指針的話,不通過從tail開始使用快慢指針遍歷是無法辦到的。
因此直接維護(hù)prev勋拟、next指針勋磕,以降低刪除操作的復(fù)雜性。 說白了就是降低刪除的復(fù)雜度
2.喚醒后續(xù)線程 而當(dāng)多線程競爭時(shí)敢靡,CLH的輪詢是非常耗費(fèi)性能的挂滓,無論是對CPU還是總線來說,都是一種巨大的壓力啸胧。
所以在CLH的prev基礎(chǔ)上增加了next

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末赶站,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子纺念,更是在濱河造成了極大的恐慌贝椿,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件陷谱,死亡現(xiàn)場離奇詭異烙博,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)烟逊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門渣窜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人宪躯,你說我怎么就攤上這事乔宿。” “怎么了访雪?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵详瑞,是天一觀的道長。 經(jīng)常有香客問我臣缀,道長蛤虐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任肝陪,我火速辦了婚禮,結(jié)果婚禮上刑顺,老公的妹妹穿的比我還像新娘氯窍。我一直安慰自己,他們只是感情好蹲堂,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布狼讨。 她就那樣靜靜地躺著,像睡著了一般柒竞。 火紅的嫁衣襯著肌膚如雪政供。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天,我揣著相機(jī)與錄音布隔,去河邊找鬼离陶。 笑死,一個胖子當(dāng)著我的面吹牛衅檀,可吹牛的內(nèi)容都是我干的招刨。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼哀军,長吁一口氣:“原來是場噩夢啊……” “哼沉眶!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起杉适,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤谎倔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后猿推,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體片习,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年彤守,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了毯侦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡具垫,死狀恐怖侈离,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情筝蚕,我是刑警寧澤卦碾,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站起宽,受9級特大地震影響洲胖,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜坯沪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一绿映、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧腐晾,春花似錦叉弦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至巨柒,卻和暖如春樱拴,著一層夾襖步出監(jiān)牢的瞬間柠衍,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工晶乔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留珍坊,地道東北人。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓瘪弓,卻偏偏與公主長得像垫蛆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子腺怯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評論 2 355

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