久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

java并發編程中悲觀鎖和樂觀鎖是什么意思

173次閱讀
沒有評論

共計 2198 個字符,預計需要花費 6 分鐘才能閱讀完成。

這篇文章主要介紹 java 并發編程中悲觀鎖和樂觀鎖是什么意思,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!

悲觀鎖

悲觀鎖是平時開發中經常用到的一種鎖,比如 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 {
 // 獲取內存,稱之為期待的內存值 E
 var5 = 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 的消耗。在這種情況下,建議可以使用悲觀鎖。

以上是“java 并發編程中悲觀鎖和樂觀鎖是什么意思”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注丸趣 TV 行業資訊頻道!

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-08-16發表,共計2198字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 延津县| 民县| 大理市| 祁连县| 玛沁县| 密云县| 沽源县| 内江市| 固原市| 沈丘县| 阿拉善右旗| 綦江县| 响水县| 泸定县| 长兴县| 云安县| 延庆县| 南汇区| 上思县| 田东县| 乐至县| 武邑县| 定南县| 新田县| 浪卡子县| 库车县| 观塘区| 探索| 镇宁| 花莲县| 西宁市| 化州市| 黔西| 岑溪市| 珲春市| 禄劝| 弥勒县| 宿松县| 甘孜| 长葛市| 门头沟区|