更新時(shí)間:2022年09月29日14時(shí)42分 來源:傳智教育 瀏覽次數(shù):
CAS(Compare and Swap),即比較并替換,是用于實(shí)現(xiàn)多線程同步的原子指令,是用于實(shí)現(xiàn)多線程同步的原子指令。
執(zhí)行函數(shù):CAS(V,E,N)
其包含3個(gè)參數(shù):
· V表示要更新的變量
· E表示預(yù)期值
· N表示新值
假定有兩個(gè)操作A和B,如果從執(zhí)行A的線程來看,當(dāng)另一個(gè)線程執(zhí)行B時(shí),要么將B全部執(zhí)行完,要么完全不執(zhí)行B,那么A和B對(duì)彼此來說是原子的。
實(shí)現(xiàn)原子操作可以使用鎖,鎖機(jī)制,滿足基本的需求是沒有問題的了,但是有的時(shí)候我們的需求并非這么簡(jiǎn)單,我們需要更有效,更加靈活的機(jī)制,synchronized關(guān)鍵字是基于阻塞的鎖機(jī)制,也就是說當(dāng)一個(gè)線程擁有鎖的時(shí)候,訪問同一資源的其它線程需要等待,直到該線程釋放鎖。
這里會(huì)有些問題:首先,如果被阻塞的線程優(yōu)先級(jí)很高很重要怎么辦?其次,如果獲得鎖的線程一直不釋放鎖怎么辦?(這種情況是非常糟糕的)。還有一種情況,如果有大量的線程來競(jìng)爭(zhēng)資源,那CPU將會(huì)花費(fèi)大量的時(shí)間和資源來處理這些競(jìng)爭(zhēng),同時(shí),還有可能出現(xiàn)一些例如死鎖之類的情況,最后,其實(shí)鎖機(jī)制是一種比較粗糙,粒度比較大的機(jī)制,相對(duì)于像計(jì)數(shù)器這樣的需求有點(diǎn)兒過于笨重。
實(shí)現(xiàn)原子操作還可以使用當(dāng)前的處理器基本都支持CAS的指令,只不過每個(gè)廠家所實(shí)現(xiàn)的算法并不一樣,每一個(gè)CAS操作過程都包含三個(gè)運(yùn)算符:一個(gè)內(nèi)存地址V,一個(gè)期望的值A(chǔ)和一個(gè)新值B,操作的時(shí)候如果這個(gè)地址上存放的值等于這個(gè)期望的值A(chǔ),則將地址上的值賦為新值B,否則不做任何操作。
CAS的基本思路就是,如果這個(gè)地址上的值和期望的值相等,則給其賦予新值,否則不做任何事兒,但是要返回原值是多少。循環(huán)CAS就是在一個(gè)循環(huán)里不斷的做cas操作,直到成功為止。
CAS是怎么實(shí)現(xiàn)線程的安全呢?語言層面不做處理,我們將其交給硬件—CPU和內(nèi)存,利用CPU的多處理能力,實(shí)現(xiàn)硬件層面的阻塞,再加上volatile變量的特性即可實(shí)現(xiàn)基于原子操作的線程安全。
CPU指令對(duì)CAS的支持
或許我們可能會(huì)有這樣的疑問,假設(shè)存在多個(gè)線程執(zhí)行CAS操作并且CAS的步驟很多,有沒有可能在判斷V和E相同后,正要賦值時(shí),切換了線程,更改了值。造成了數(shù)據(jù)不一致呢?答案是否定的。
因?yàn)镃AS是一種系統(tǒng)原語,原語屬于操作系統(tǒng)用語范疇,是由若干條指令組成的,用于完成某個(gè)功能的一個(gè)過程,并且原語的執(zhí)行必須是連續(xù)的,在執(zhí)行過程中不允許被中斷,也就是說CAS是一條CPU的原子指令,不會(huì)造成所謂的數(shù)據(jù)不一致問題。
悲觀鎖,樂觀鎖
說到CAS,不得不提到兩個(gè)專業(yè)詞語:悲觀鎖,樂觀鎖。我們先來看看什么是悲觀鎖,什么是樂觀鎖。
悲觀鎖顧名思義,就是比較悲觀的鎖,總是假設(shè)最壞的情況,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人會(huì)修改,所以每次在拿數(shù)據(jù)的時(shí)候都會(huì)上鎖,這樣別人想拿這個(gè)數(shù)據(jù)就會(huì)阻塞直到它拿到鎖(共享資源每次只給一個(gè)線程使用,其它線程阻塞,用完后再把資源轉(zhuǎn)讓給其它線程)。傳統(tǒng)的關(guān)系型數(shù)據(jù)庫里邊就用到了很多這種鎖機(jī)制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。Java中synchronized和ReentrantLock等獨(dú)占鎖就是悲觀鎖思想的實(shí)現(xiàn)。
而樂觀鎖反之,總是假設(shè)最好的情況,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人不會(huì)修改,所以不會(huì)上鎖,但是在更新的時(shí)候會(huì)判斷一下在此期間別人有沒有去更新這個(gè)數(shù)據(jù),可以使用版本號(hào)機(jī)制和CAS算法實(shí)現(xiàn)。樂觀鎖適用于多讀的應(yīng)用類型,這樣可以提高吞吐量,像數(shù)據(jù)庫提供的類似于write_condition機(jī)制,其實(shí)都是提供的樂觀鎖。我們今天講的CAS就是樂觀鎖。
由于CAS操作屬于樂觀派,它總認(rèn)為自己可以成功完成操作,當(dāng)多個(gè)線程同時(shí)使用CAS操作一個(gè)變量時(shí),只有一個(gè)會(huì)勝出,并成功更新,其余均會(huì)失敗,但失敗的線程并不會(huì)被掛起,僅是被告知失敗,并且允許再次嘗試,當(dāng)然也允許失敗的線程放棄操作?;谶@樣的原理,CAS操作即使沒有鎖,同樣知道其他線程對(duì)共享資源操作影響,并執(zhí)行相應(yīng)的處理措施。同時(shí)從這點(diǎn)也可以看出,由于無鎖操作中沒有鎖的存在,因此不可能出現(xiàn)死鎖的情況,也就是說無鎖操作天生免疫死鎖。
CAS 的優(yōu)點(diǎn)
非阻塞的輕量級(jí)樂觀鎖, 通過CPU指令實(shí)現(xiàn), 在資源競(jìng)爭(zhēng)不激烈的情況下性能高, 相比synchronize重量級(jí)悲觀鎖, synchronize有復(fù)雜的加鎖, 解鎖和喚醒線程操作。
北京校區(qū)