JAVA面試中常常問到的無鎖CAS是什麼?

哎喲JAVA不錯哦


在緩存領域有一對奇葩,多線程的緩存和單線程的redis,而兩者的性能是差不多的,之所以redis能憑藉單線程提供強大的性能並且線程安全操作:

一是不存在多線程直接切換的資源開銷,

二是大部分的指令都是原子的,原子的指令擁有更高的效率,並且保證線程安全!

在java中的原子操作主要封裝在併發包下,以Atomic打頭的類中,如下截圖:


觀察這些類發現,其中的原子操作主要依賴於UnSafe包中類似unsafe.compareAndSwapInt這樣的算法,取單詞首字母,也即是CAS操作,這也是實現無鎖操作保證線程安全的基石,樂觀鎖因為建立在CPU的底層指令原子操作,效率比起同步鎖相當高;

CAS:compare,and,swap:顧名思義,就是比較並交換,這屬於一種樂觀鎖思想,悲觀鎖通常是把共享資源的持有者當做互斥的,由此保證針對共享資源操作的只會是持有鎖的程序!

而樂觀鎖之所以稱為樂觀,就是假設數據在操作之前都是沒有被修改過的,如果已經被修改過,則不進行操作,降低了阻塞的可能性!

CAS的思想在sql操作中常常用到,比如未付款status=1,已付款status=2,sql:update set status=2,version=version+1 where id = xx and status =1 and version=${version},即是如果是還未付款的狀態則付款,如果已經付過款(status=2),則操作失敗;

但是CAS也存在問題:

①,ABA問題,比如上面的sql,如果status是會從1(A)到2(B)再到1(A)的,那麼就會存在線程一已經從1->2->1了,而線程二還認為整個數據都沒有變過,繼續修改數據;

②,性能浪費:CAS的操作依賴於自旋(不斷循環到滿足條件),如果條件一直不滿足,則CPU開銷一直存在;

下面以AtomicInteger 為例說下CAS的應用類特性:


1,從構造器和get,set方法來看,處理的值需要修飾為內存可見的valatile。

2,大多數的方法都是使用了unsafe中的compareAndSwap方法,都是native方法,說明是底層封裝;

直接看案例,如下截圖:

案例中的AtomicInteger,如果改成Integer,結果基本都會小於100,說明數據計算錯誤了!

CAS作為AQS模型的基石,兩者都是面試過程中常常問到的,下次再講AQS,喜歡的童鞋歡迎點贊關注。。


分享到:


相關文章: