CAS以及在Java併發機制中的使用

Java 併發編程中有介紹CAS實現鎖的機制,後面再看了一些編譯原理方法的書,對鎖的實現有一些基本瞭解。

提高併發減少上下文切換的方法:

  • 無鎖併發編程:按Hash算法取模分段,不同的線程處理不同段數據。
  • CAS算法:CAS算法更新數據,無需加鎖。
  • 使用最少線程:儘量用少的線程,不要造成等待。
  • 協程:在單線程裏實現多任務的調度。

Java併發機制的底層實現

  • Volatile:將當前處理器緩存行數據回寫到系統內存,並讓其他緩存失效。
  • synchronized:同步代碼塊,鎖定對象頭。monitorenter和monitorexit指令。
  • 原子操作:通過鎖和循環CAS的方式來實現原子操作。

JVM內部實現了很多種鎖機制,有偏向鎖、輕量級鎖和互斥鎖。有意思的是除了偏向鎖,JVM實現鎖的方式都用了循環CAS,即當一個線程想進入同步塊的時候使用循環CAS的方式來獲取鎖,當它退出同步塊的時候使用循環CAS釋放鎖。

單應用部署可以通過Java鎖現實線程同步,當部署微服務時,需要鎖定庫存量時就需要想其他辦法,Redis CAS操作實現樂觀鎖。

Redis樂觀鎖工作機制:

watch指令在Redis事物中提供了CAS的行爲。watch 命令會監視給定的每一個key,當exec時如果監視的任一個key自從調用watch後發生過變化,則整個事務會回滾,不執行任何動作。注意watch的key是對整個連接有效的,事務也一樣。如果連接斷開,監視和事務都會被自動清除。當然exec,discard,unwatch命令,及客戶端連接關閉都會清除連接中的所有監視。還有,如果watch一個不穩定(有生命週期)的key並且此key自然過期,exec仍然會執行事務隊列的指令。

實戰應用:

當設計一個秒殺系統時候,爲防止商品數量被超額購買,可以預先把庫存數量加載到redis中,活動開始後服務端每次都通過Redis控制庫存數量,同時使用watch命令實現CAS鎖,如何Redis返回正常則走正常流程,如果否,則重試進入秒殺流程。通過Redis可以有效防止商品庫存爆掉。

隨想

我們在餓了麼上面購買商品時候,涉及到支付,當我們購買一個商品後,因爲某個原因沒有支付,這時候訂單會變成等待支付,這時候商品數量是應該減還是不減了。這個問題應該是一個產品問題,但是對應到代碼層面我們會認爲這就是悲觀鎖和樂觀鎖的設計區別。假定對系統數據流程要求很嚴格,可以直接使用悲觀鎖方式,直接先鎖定數據,即庫存數量減少,如果失敗則回退庫存,這樣設計就會讓很多用戶因庫存不夠被排斥在外無法購買。樂觀鎖則只在支付完成後減庫存,中間可以不斷重試。支付的過程也是一個事務的過程,一般涉及2個步驟,預提交支付和最終確認支付,可能還涉及到支付餘額不足的問題,都是在支付環節需要解決的問題。

 

 

 

 

 

 

 

 

 

 

參考:

https://www.jianshu.com/p/ae25eb3cfb5d

https://www.cnblogs.com/martinzhang/p/3415204.html

https://www.cnblogs.com/huobi/p/9844755.html

Java內存模型的基礎以及內存語義

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章