日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

乐观锁和悲观锁_什么是悲观锁和乐观锁?

發布時間:2024/7/19 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 乐观锁和悲观锁_什么是悲观锁和乐观锁? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

思維導圖

文章已收錄Github精選,歡迎Star:https://github.com/yehongzhi/learningSummary

悲觀鎖

悲觀鎖是平時開發中經常用到的一種鎖,比如ReentrantLock和synchronized等就是這種思想的體現,它總是假設別的線程在拿線程的時候都會修改數據,所以每次拿到數據的時候都會上鎖,這樣別的線程想拿這個數據就會被阻塞。如圖所示:

synchronized是悲觀鎖的一種實現,一般我們都會有這樣使用:

private static Object monitor = new Object();public static void main(String[] args) throws Exception {//鎖一段代碼塊synchronized (monitor){} } //鎖實例方法,鎖對象是this,即該類實例本身 public synchronized void doSome(){} //鎖靜態方法,鎖對象是該類,即XXX.class public synchronized static void add(){}

我們以最簡單的同步代碼塊來分析,其實就是將synchronized作用于一個給定的實例對象monitor,即當前實例對象就是鎖對象,每次當線程進入synchronized包裹的代碼塊時就會要求當前線程持有monitor實例對象鎖,如果當前有其他線程正持有該對象鎖,那么新到的線程就必須等待,這樣也就保證了每次只有一個線程執行synchronized內包裹的代碼塊。

從上面的分析中可以看出,悲觀鎖是獨占和排他的,只要操作資源都會對資源進行加鎖。假設讀多寫少的情況下,使用悲觀鎖的效果就不是很好。這時就引出了接下來要講的樂觀鎖。

樂觀鎖

樂觀鎖,顧名思義它總是假設最好的情況,線程每次去拿數據時都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,如果這個數據沒有被更新,當前線程將自己修改的數據成功寫入。如果數據已經被其他線程更新,則根據不同的實現方式執行不同的操作(例如報錯或者自動重試)。如圖所示:

一般樂觀鎖在java中是通過無鎖編程實現的,最常見的就是CAS算法,比如Java并發包中的原子類的遞增操作就是通過CAS算法實現的。

CAS算法,其實就是Compare And Swap(比較與交換)的意思。目的就是將內存的值更新為需要的值,但是有個條件,內存值必須與期待的原內存值相同。展開來說,我們有三個變量,內存值M,期望的內存值E,更新值U,只有當M==E時,才會將M更新為U。

CAS算法實現的樂觀鎖在很多地方有應用,比如并發包的原子類AtomicInteger類。在自增的時候就使用到CAS算法。

public final int getAndIncrement() {return unsafe.getAndAddInt(this, valueOffset, 1); }//var1 是this指針 //var2 是偏移量 //var4 是自增量 public final int getAndAddInt(Object var1, long var2, int var4) {int var5;do {//獲取內存,稱之為期待的內存值Evar5 = this.getIntVolatile(var1, var2);//var5 + var4的結果是更新值U//這里使用JNI方法,每個線程將自己內存中的內存值M與var5期望值比較,//如果相同則更新為var5 + var4,返回true跳出循環。//如果不相同,則把內存值M更新為最新的內存值,然后自旋,直到更新成功為止} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));//返回更新后的值return var5; }public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

所以可以看出CAS算法其實是無鎖的。好處是在讀多寫少的情況下,性能是比較好的。那么CAS算法的缺點其實也是很明顯的。

  • ABA問題。線程C將內存值A改成了B后,又改成了A,而線程D會認為內存值A沒有改變過,這個問題就稱為ABA問題。解決辦法很簡單,在變量前面加上版本號,每次變量更新的時候變量的版本號都+1,即A->B->A就變成了1A->2B->3A。
  • 在寫多讀少的情況下,也就是頻繁更新數據,那么會導致其他線程經常更新失敗,那么就會進入自旋,自旋時會占用CPU資源。如果資源競爭激烈,多線程自旋的時間長,導致消耗資源。

使用場景

在讀多寫少的場景下,更新時很少發生沖突,使用樂觀鎖,減少了上鎖和釋放鎖的開銷,可以有效地提升系統的性能。

相反,在寫多讀少的場景下,如果使用樂觀鎖會導致更新時經常產生沖突,然后線程會循環重試,這樣會增大CPU的消耗。在這種情況下,建議可以使用悲觀鎖。

總結

在日常的開發中,悲觀鎖和樂觀鎖應該是見得最多,用得最多的鎖,比如最常見的synchronized和ReentrantLock是悲觀鎖,并發包中的原子類和ConcurrentHashMap則用了樂觀鎖。鎖的實現并不復雜,關鍵是搞懂這兩種鎖的思想,這樣才能在合適的地方使用合適的鎖。

這篇文章就講到這里了,希望看完后能有所收獲,感謝你的閱讀。

覺得有用就點個贊吧,你的點贊是我創作的最大動力~

我是一個努力讓大家記住的程序員。我們下期再見!!!

能力有限,如果有什么錯誤或者不當之處,請大家批評指正,一起學習交流!

總結

以上是生活随笔為你收集整理的乐观锁和悲观锁_什么是悲观锁和乐观锁?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。