1. 程式人生 > >Java併發程式設計之CAS第一篇-什麼是CAS

Java併發程式設計之CAS第一篇-什麼是CAS

Java併發程式設計之CAS第一篇-什麼是CAS

通過前面幾篇的學習,我們對併發程式設計兩個高頻知識點了解了其中的一個—volatitl。從這一篇文章開始,我們將要學習另一個知識點—CAS.本篇是《凱哥併發程式設計學習》系列之《CAS系列》教程的第一篇:什麼是CAS。

本文主要內容:

生活中舉例;CAS定義;CAS程式碼演示。

一:生活中的例子

在電影《智取威虎山》中,楊子榮進入威虎山的時候,土匪說:天王蓋地虎,楊子榮對:寶塔鎮河妖。類似這樣的黑話,幾個土匪和楊子榮對過之後,座山雕,三爺才發話:這麼說,你是徐旅長的人了。相信電影中這段對黑話,大家都看過。有沒有感覺很過癮呢?那麼問題來了,為什麼幾個人對過黑話之後,就能確定來者身份呢?因為在那個時候,佔山為王,各個山頭都有老大,但是又要和其他山頭交流,不能用明話來說。於是大家就編了一些黑話。根據黑話不同,來確認對方的身份。

這個過程如果站在計算機多執行緒併發程式設計角度來理解的話,可以這麼來理解。黑話庫就是主記憶體中變數楊子榮和其他土F是不同的執行緒。,他們之間的黑話就是各自從主記憶體複製的變數副本。當T匪A(也就是執行緒A):天王蓋地虎是自己的副本的資料,想要更新為:寶塔鎮河妖。當楊子榮回答後,T匪A就拿著,天王蓋地虎,寶塔鎮河妖,這句話和黑話庫(主記憶體)對比,對比上,則說明楊子榮說的對。允許接下來對話。如果這個不好理解的話,我們在舉個例子。

修改登陸密碼,這個大家都操作過吧。無論是各個APP還是各地網站都支援修改密碼。那麼修改密碼的三要素是什麼大家知道嗎:資料庫儲存的原祕密;使用者輸入的原祕密;以及將要更新的密碼。資料儲存的原祕密(主記憶體),使用者輸入的原祕密(執行緒副本)。當資料庫中儲存的和使用者輸入的原密碼對比相同的時候,才可以將原密碼更新為新密碼。否則就不能更新。

從上面兩個例子我們可以看到,要想成功,需要三個變數:主記憶體變數值、執行緒自己工作區副本值以及要更新的資料值。如果有了上面三個概念,我們就來看看什麼是CAS

二:什麼是CAS

CAS定義:

CAS:Compare and Swap 三個字母的縮寫。

是什麼意思呢?Compare:比較 Swap:交換。所以CAS即為:比較並交換的意思。

需要注意:and 是並的意思。在邏輯運算中,並的意思:只有都成立了才可以執行下面操作。

那麼在Java併發中為什麼會大量的使用到CAS呢?

那是因為CAS是無鎖的一種演算法。為了解決多執行緒並行(併發)情況下使用鎖的話,效能消耗的一種機制。

CAS操作流程:

CAS操作包含了三個操作資料。分別是:主記憶體資料值或主記憶體位置(V)、執行緒工作區副本更新前的資料值或者是預期值(A)以及要更新成的新值(B)。

操作流程:

執行緒M在更新的共享變數的時候,會拿著自己工作區變數副本A的值,假設是1,將要更新的值B。假設是2.去更新主記憶體共享變數V的時候,會先拿著V和A比較。如果V==A的時候,才會將主記憶體V的值換成B。否則就會重新獲取主記憶體的值,進行自旋操作,知道成功位置。

簡單理解:我(執行緒M,工作區值為A)認為主記憶體V中的共享變數值是(包含)A,如果 V的值是A,那麼就將B替換V。如果不是,就不更新V的值,只要告訴我V的最新值。我自己自旋操作,自己玩。

三:CAS程式碼演示

我們知道在JUC下,有個原子包,就在atomic包下,我們用來演示CAS程式碼就用AtomicInteger這個類來演示。程式碼如下圖:

 

問題:

在12和13行,執行後的結果是什麼呢?

 

true 執行後。當前i的值為:2020

false 執行後。當前i的值為:2020

為什麼會是這樣呢?

執行結果分析

我們來分析:

在11行的時候,聲明瞭變數i.並賦值為1(即V),然後第12行,拿著預期值1(即A),和將要更新的值2020(即B).進行CAS之後,因為1==1也就是V==A。這個中情況下,就會把2020重新賦值給V。所以,第12行輸出的就是true和2020;

在第13行假設是執行緒2來訪問。執行緒2自己工作空間變數副本依然是1,更行值是1024.這個時候進行CAS的時候,因為現在主記憶體V的值是2020,所以2020 != 1也就是V != A。這個時候,V的值不能被更新,所以第13行輸出的是就是false和2020.

在看下面:

 

問題:第14行輸出的是什麼呢 ?

我們來看看執行結果:

 

為什麼呢?大家可以嘗試這去分析分析。(PS:提示,看看上文CAS定義和CAS操作流程來分析)。

在下一節中,凱哥(凱哥Java:kaigejava)將和大家嘮嘮CAS的原理。為什麼,如果不加鎖的話,volatile不能保證原子性,但是atomic包下的類就可以保證原子性呢?我們從AtomicInteger原始碼追根溯源吧。