CAS樂觀鎖解決併發問題的一次實踐

前言

最近作新項目,貨幣充值消耗,送禮競爭勳章等都使用了CAS解決併發問題,因此作一下筆記,談談CAS,你們一塊兒互相學習。算法

樂觀鎖,悲觀鎖:

討論CAS的話,先來講有一下樂觀鎖,悲觀鎖。數據庫

悲觀鎖:每次去取數據,很悲觀,都以爲會被別人修改,因此在拿數據的時候都會上鎖。簡言之,共享資源每次都只給一個線程使用,其餘線程阻塞,等第一個線程用完後再把資源轉讓給其餘線程。synchronized和ReentranLock等都是悲觀鎖思想的體現。併發

樂觀鎖:每次去取數據,都很樂觀,以爲不會被被人修改。所以每次都不上鎖,可是在更新的時候,就會看別人有沒有在這期間去更新這個數據,若是有更新就從新獲取,再進行判斷,一直循環,直到拿到沒有被修改過的數據。CAS(Compare and Swap 比較並交換)就是樂觀鎖的一種實現方式。工具

CAS算法:

CAS涉及三個操做數

1.須要讀寫的內存地址V學習

2.進行比較的預期原值A線程

3.擬寫入的新值Bcdn

若是內存位置的值V與預期原A值相匹配,那麼處理器會自動將該位置值更新爲新值B。CAS思想:要進行更新時,認爲位置V上的值仍是跟A值相等,若是是是相等,就認爲它沒有被別的線程更改過,便可更新爲B值。不然,認爲它已經被別的線程修改過,不更新爲B的值,返回當前位置V最新的值。blog

JDK源碼中,CAS思想體現:

反編譯Unsafe類(用Java Decompiler工具) 內存

從源碼中能夠發現,內部使用自旋的方式進行CAS更新

業務場景以及CAS的應用:

假設多人A,B,C等給D送禮,送總價值最多的那我的,能夠成爲佩帶D的守護皇冠,D的守護皇冠有且只有一個。若是他們同時在給D送禮,送禮價值互相超越,即存在併發問題。資源

解決思路: 參考樂觀鎖原理

  • 設置樂觀鎖失敗後嘗試次數n次
  • 先查詢舊的守護者,即舊的送禮最大價值者。
  • 若是當前舊的守護者不爲空,構造當前送禮者爲新守護者。
  • 將新的守護者去跟舊的守護者比較送禮的價值,嘗試更新數據庫。
  • 若是發現更新時,舊的最大送禮價值發生改變了,放棄更新,退出循環,從新嘗試(n--)。
  • 若是當前舊的守護者爲空,表示之前尚未守護,直接將新的守護插入表。
  • 若是插入表失敗,表示在插入過程當中,數據被更改了,代表有新的記錄搶先成爲守護。
  • 那麼,從新嘗試(n--),直到次數n用完。

搶佔守護流程圖:

代碼實現:

CAS存在的一些問題:

1.ABA問題,

併發環境下,假設初始條件是A,去修改數據時,發現是A就會執行修改。可是看到的雖然是A,中間可能發生了A變B,B又變回A的狀況。此時A已經非彼A,數據即便成功修改,也可能有問題。

2.CPU開銷

自旋CAS,若是一直循環執行,一直不成功,會給CPU帶來很是大的執行開銷。因此上面搶佔守護的例子,設置了嘗試的執行次數n,避免一直循環

相關文章
相關標籤/搜索