在JDK1.5引入的 J.U.C包中的原子類以及Lock等都是基于 volatile 關(guān)鍵結(jié)合 CAS 操作實現(xiàn)的愿棋,為了能夠搞明白 原子類以及 Lock鎖的原理首先要了解 volatile 原理以及 CAS原理招盲,上篇文章我們說了volatile關(guān)鍵字,這篇咱們就聊聊 什么是 CAS 操作算谈。
悲觀鎖與樂觀鎖
在說CAS操作之前咱們先說一下什么是悲觀鎖和樂觀鎖涩禀。
悲觀鎖
悲觀鎖就是總是加鎖最壞的情況,所以每次去拿數(shù)據(jù)時都認(rèn)為別人會修改然眼,所以每次操作共享數(shù)據(jù)時都會上鎖艾船,這樣當(dāng)別人需要訪問共享數(shù)據(jù)時,就必須阻塞等待高每,直到它拿到鎖屿岂。傳統(tǒng)的關(guān)系型數(shù)據(jù)庫里面就用到了很多這種鎖機(jī)制,比如行鎖鲸匿、表鎖等爷怀,都是在操作之前先加上鎖。在Java中 synchronized 和 ReentrantLock 等都是獨占的带欢,也就是悲觀鎖运授。
悲觀鎖可以理解為就是 “總有刁民想害朕”。
樂觀鎖
樂觀鎖就是總是情況最好的乔煞,每次去拿共享數(shù)據(jù)的時候認(rèn)為別人不會修改吁朦,所以不會上鎖,但是在更新數(shù)據(jù)的時候會判斷一下在此期間別人是否更改了數(shù)據(jù)渡贾。一般可以通過版本號和 CAS算法實現(xiàn)逗宜。樂觀鎖適用于讀多寫少的場景,這樣可以提供吞吐量空骚。
什么是CAS
CAS 即 Compare And Swap (比較與交換)纺讲,是一種有名的無鎖算法。CAS算法主要涉及到三個參數(shù):
- 主內(nèi)存中存放的的值V囤屹,也就是線程共享的值熬甚。
- 線程上次從內(nèi)存中讀取的V值 A,線程私有的牺丙,存放在線程棧幀中则涯,或者CPU緩存中的值复局。
- 需要寫入主內(nèi)存改些V的值B冲簿,線程對A計算后的值。
大致流程如下所示:
CAS帶來的三大問題
ABA問題
因為CAS需要在操作值的時候亿昏,檢查值有沒有發(fā)生變化峦剔,如果沒有發(fā)生變化則更新,但是如果一個值原來是A角钩,變成了B吝沫,又變成了A呻澜,那么CAS進(jìn)行檢查的時候發(fā)現(xiàn)它的值沒有發(fā)生變化,但是實際上卻變化了惨险。ABA問題的解決思路就是使用版本號羹幸。在變量前面加上版本號,每次變量更新的時候把版本號加1辫愉,那么A->B->A就會變成1A->2B->3A栅受。從Java 1.5開始,JDK的Atomic包里提供了一個類AtomicStampedReference來解決ABA問題恭朗。這個類的compareAndSet方法的作用是首先檢查當(dāng)前引用是否等于預(yù)期引用屏镊,并且檢查當(dāng)前的標(biāo)志是否等于預(yù)期標(biāo)志,如果全部相等痰腮,則以原子方式將該應(yīng)用和該標(biāo)志的值設(shè)置為給定的更新值而芥。
開銷大的問題
自旋CAS如果長時間不成功,會給CPU帶來非常大的執(zhí)行開銷膀值,如果JVM能支持處理器提供的pause指令棍丐,那么效率會有一定的提升。pause指令有兩個作用:
第一沧踏,它可以延遲流水線執(zhí)行指令(de-pipeline)骄酗,使CPU不會消耗過多的執(zhí)行資源,延遲的時間取決于具體實現(xiàn)的版本悦冀,在一些處理器上延遲時間是零趋翻;
第二,它可以避免在循環(huán)的時候因內(nèi)存順序沖突(Memory Order Violation)而引起CPU流水線被清空盒蟆,從而提高CPU的實行效率踏烙。
只能保證一個共享變量的原子操作
當(dāng)對一個共享變量執(zhí)行操作時,我們可以使用循環(huán)CAS的方式來保證原子操作历等,但是對多個共享變量操作時讨惩,循環(huán)CAS就無法保證操作的原子性,這個時候可以用鎖寒屯。還有一個取巧的辦法荐捻,就是把多個共享變量合并成一個共享變量來操作。比如寡夹,有兩個共享變量i=2,j=a,合并一下ji=2a,然后用CAS來操作ij处面。從Java 1.5開始,JDK提供了AtomicReference類來保證引用對象之前的原子性菩掏,就可以把多個變量放在一個對象里來進(jìn)行CAS操作魂角。
總結(jié)
本篇文章首先介紹了什么是悲觀鎖和樂觀鎖,然后介紹了 CAS 原理智绸,CAS 就是 比較并交換野揪,也就是在寫入時先比較 主內(nèi)存中值是否跟之前讀取的舊值相等,如果相等就更新斯稳,如果不相等就再次讀取計算海铆,循環(huán)往復(fù)。CAS 在提高性能的同時挣惰,也帶來了三大問題游添。明白三大問題能夠更好的使用 CAS操作,以及后續(xù)的 原子操作類通熄。