天天看點

CAS場景及解決ABA問題

假如你往地上仍1萬塊錢,是不是一定會丢呢?這要看情況了,如果是在人來人往的都市,可以說肯定會丢的。如果你跑到無人區扔地上,可以說肯定不會丢。

可以看到,都是把東西無保護的放到公共區域裡,結果卻相差很大。這說明安全問題還和公共區域的環境狀況有關系。

比如我把資料放到公共區域的堆記憶體中,但是始終都隻會有1個線程,也就是單線程模型,那這資料肯定是安全的。

再者說,2個線程操作同一個資料和200個線程操作同一個資料,這個資料的安全機率是完全不一樣的。肯定線程越多資料不安全的機率越大,線程越少資料不安全的機率越小。取個極限情況,那就是隻有1個線程,那不安全機率就是0,也就是安全的。

可能你又猜到了我想表達的内容了,沒錯,就是cas。可能大家覺得既然鎖可以解決問題,那就用鎖得了,為啥又冒出了個cas呢?

那是因為鎖的擷取和釋放是要花費一定代價的,如果線上程數目特别少的時候,可能根本就不會有别的線程來操作資料,此時你還要擷取鎖和釋放鎖,可以說是一種浪費。

針對這種“地廣人稀”的情況,專門提出了一種方法,叫cas(compare and swap)。就是在并發很小的情況下,資料被意外修改的機率很低,但是又存在這種可能性,此時就用cas。

假如一個線程操作資料,幹了一半活,累了,想要去休息。(貌似今天的線程體質都不太好)。于是它記錄下目前資料的狀态(就是資料的值),回家睡覺了。

醒來後打算繼續接着幹活,但是又擔心資料可能被修改了,于是就把睡覺前儲存的資料狀态拿出來和現在的資料狀态比較一下,如果一樣,說明自己在睡覺期間,資料沒有被人動過(當然也有可能是先被改成了其它,然後又改回來了,這就是aba問題了),那就接着繼續幹。如果不一樣,說明資料已經被修改了,那之前做的那些操作其實都白瞎了,就幹脆放棄,從頭再重新開始處理一遍。

是以cas這種方式适用于并發量不高的情況,也就是資料被意外修改的可能性較小的情況。如果并發量很高的話,你的資料一定會被修改,每次都要放棄,然後從頭再來,這樣反而花費的代價更大了,還不如直接加鎖呢。

這裡再解釋下aba問題,假如你睡覺前資料是5,醒來後資料還是5,并不能肯定資料沒有被修改過。可能資料先被修改成8然後又改回到5,隻是你不知道罷了。對于這個問題,其實也很好解決,再加一個版本号字段就行了,并規定隻要修改資料,必須使版本号加1。

這樣你睡覺前資料是5版本号是0,醒來後資料是5版本号是0,表明資料沒有被修改。如果資料是5版本号是2,表明資料被改動了2次,先改為其它,然後又改回到5。

我再次相信聰明的你已經發現了,這裡的cas其實就是樂觀鎖,上一種方案裡的擷取鎖和釋放鎖其實就是悲觀鎖。樂觀鎖持樂觀态度,就是假設我的資料不會被意外修改,如果修改了,就放棄,從頭再來。悲觀鎖持悲觀态度,就是假設我的資料一定會被意外修改,那幹脆直接加鎖得了。

部落客寫的非常好,我隻是拿出來一部分覺得例子和講解非常好,轉載來和大家一起學習!!