1. 程式人生 > 其它 >JAVA多執行緒-鎖

JAVA多執行緒-鎖

1. 樂觀鎖

樂觀鎖是一種樂觀思想,認為讀多寫少。遇到併發寫的可能性低,每次去拿資料的時候都認為別人不會去修改,所以不會上鎖。但是在更新的時候會判斷一下在此期間別人有沒有去更新這個資料,才去在寫時先讀取當前版本號,然後枷鎖操作(比較更上一次版本號,如果一樣則更新),如果失敗,則要重複讀-比較-寫的操作。

JAVA中樂觀鎖基本都是通過CAS操作實現,CAS是一種原子更新操作,比較當前值跟傳入的值是否一樣,一樣則更新,否則失敗。

CAS詳解,https://blog.csdn.net/qq_41282026/article/details/98089231

2. 悲觀鎖

悲觀鎖是一種悲觀思想,認為寫多讀少,遇到併發寫的可能性高,每次去拿資料的時候都認為別人會修改,所以每次在寫的時候都會去上鎖,這樣別人想讀寫這個資料就會 block 直到拿到鎖。java中悲觀鎖就是 Synchronized, AQS框架下的鎖則先嚐試 cas 樂觀鎖去獲取鎖,獲取不到才會轉為悲觀鎖,如 Retreenlock。

3.自旋鎖

如果持有鎖的執行緒能在很短時間內釋放鎖資源,那麼那些等待競爭鎖的執行緒就不需要做核心態和使用者態的切換進入阻塞掛起狀態,他們只需要等一等(自旋),等待持有鎖的執行緒釋放後即可立即獲取鎖,這樣寄避免了使用者執行緒和核心的切換消耗。

執行緒自旋是需要消耗CPU的,如果一直獲取不到鎖,那麼執行緒會一直佔用CPU,所以需要設定一個自旋等待的最大時間。如果持有鎖的執行緒執行時間超過最大時間仍沒有釋放鎖,就會導致其他爭用鎖的執行緒在最大等待時間內還是獲取不到鎖,這是爭用執行緒會停止自旋進入阻塞狀態。

自旋鎖的優缺點:

  • 於競爭不激烈,且佔用鎖的時間非常短的程式碼塊來說效能能大幅度的提升,自旋鎖儘可能的減少執行緒的阻塞,自旋鎖的消耗小於執行緒阻塞掛起再喚醒的操作消耗,這些操作會導致執行緒發生兩次上下文切換。

  • 如果鎖競爭較為激烈,或者持有鎖的執行緒需要長時間佔用鎖執行同步程式碼塊,這時候及不適合使用自旋鎖。因為自旋鎖在獲取鎖之前需要一直佔用CPU做無用功,同時又大量的執行緒在競爭一個鎖,會導致獲取鎖的時間很長,執行緒自旋的消耗大於阻塞掛起操作消耗 ,其他需要CPU的執行緒又得不到CPU,造成CPU的浪費。

自旋鎖的開啟

JDK1.6中:-XX:+UseSpining 開啟

-XX:PreBlockSpin=10設定自旋次數為10次

JDK1.7後去掉此引數,有JVM控制