欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中的CAS鎖機制(無鎖、自旋鎖、樂觀鎖、輕量級鎖)詳解

 更新時間:2024年01月16日 10:54:25   作者:user2025  
這篇文章主要介紹了Java中的CAS鎖機制(無鎖、自旋鎖、樂觀鎖、輕量級鎖)詳解,CAS算法的作用是解決多線程條件下使用鎖造成性能損耗問題的算法,保證了原子性,這個原子操作是由CPU來完成的,需要的朋友可以參考下

什么是CAS機制(compare and swap)

CAS算法的作用:解決多線程條件下使用鎖造成性能損耗問題的算法,保證了原子性,這個原子操作是由CPU來完成的

CAS的原理:CAS算法有三個操作數(shù),通過內(nèi)存中的值(V)、預(yù)期原始值(A)、修改后的新值。

(1)如果內(nèi)存中的值和預(yù)期原始值相等, 就將修改后的新值保存到內(nèi)存中。

(2)如果內(nèi)存中的值和預(yù)期原始值不相等,說明共享數(shù)據(jù)已經(jīng)被修改,放棄已經(jīng)所做的操作,然后重新執(zhí)行剛才的操作,直到重試成功。

注意:

(1)預(yù)期原始值(A)是從偏移位置讀取到三級緩存中讓CPU處理的值,修改后的新值是預(yù)期原始值經(jīng)CPU處理暫時存儲在CPU的三級緩存中的值,而內(nèi)存指定偏移位置中的原始值。

(2)比較從指定偏移位置讀取到緩存的值與指定內(nèi)存偏移位置的值是否相等,如果相等則修改指定內(nèi)存偏移位置的值,這個操作是操作系統(tǒng)底層匯編的一個原子指令實現(xiàn)的,保證了原子性

  • JVM中CAS是通過UnSafe類來調(diào)用操作系統(tǒng)底層的CAS指令實現(xiàn)。
  • CAS基于樂觀鎖思想來設(shè)計的,其不會引發(fā)阻塞,synchronize會導(dǎo)致阻塞。

原子類

java.util.concurrent.atomic包下的原子類都使用了CAS算法。而java.util.concurrent中的大多數(shù)類的實現(xiàn)都直接或間接的使用了這些原子類。 Unsafe類使Java擁有了類似C語言指針操作內(nèi)存空間的能力,同時也帶來了指針的安全問題。

AtomicInteger原子類

AtomicInteger等原子類沒有使用synchronized鎖,而是通過volatile和CAS(Compare And Swap)解決資源的線程安全問題。

(1)volatile保證了可見性和有序性

(2)CAS保證了原子性,而且是無鎖操作,提高了并發(fā)效率。

//創(chuàng)建Unsafe類的實例
private static final Unsafe unsafe = Unsafe.getUnsafe();
//成員變量value是在內(nèi)存地址中距離當(dāng)前對象首地址的偏移量, 具體賦值是在下面的靜態(tài)代碼塊中中進行的
private static final long valueOffset;
static {
    try {
        //類加載的時候,在靜態(tài)代碼塊中獲取變量value的偏移量
        valueOffset = unsafe.objectFieldOffset
            (AtomicInteger.class.getDeclaredField("value"));
    } catch (Exception ex) { throw new Error(ex); }
}
// 當(dāng)前AtomicInteger原子類的value值
private volatile int value;
//類似于i++操作
public final int getAndIncrement() {
	//this代表當(dāng)前AtomicInteger類型的對象,valueOffset表示value成員變量的偏移量
    return unsafe.getAndAddInt(this, valueOffset, 1);
}
================================上方為AtomicInteger類中的方法,下方為Unsafe類中的方法=========================================================
//此方法的作用:獲取內(nèi)存地址為原子對象首地址+原子對象value屬性地址偏移量, 并將該變量值加上delta
public final int getAndAddInt(Object obj, long offset, int delta) {
    int v;
    do {
    	//通過對象和偏移量獲取變量值作為期望值,在修改該內(nèi)存偏移位置的值時與原始進行比較
    	//此方法中采用volatile的底層原理,保證了內(nèi)存可見性,所有線程都從內(nèi)存中獲取變量vlaue的值,所有線程看到的值一致。
        v= this.getIntVolatile(obj, offset);
    /*
	while中的compareAndSwapInt()方法嘗試修改v的值,具體地, 該方法也會通過obj和offset獲取變量的值
	如果這個值和v不一樣, 說明其他線程修改了obj+offset地址處的值, 此時compareAndSwapInt()返回false, 繼續(xù)循環(huán)
	如果這個值和v一樣, 說明沒有其他線程修改obj+offset地址處的值, 此時可以將obj+offset地址處的值改為v+delta, compareAndSwapInt()返回true, 退出循環(huán)
	Unsafe類中的compareAndSwapInt()方法是原子操作, 所以compareAndSwapInt()修改obj+offset地址處的值的時候不會被其他線程中斷
	*/
    } while(!this.compareAndSwapInt(obj, offset, v, v + delta));
    return v;
}

操作步驟:

(1)獲取AtomicInteger對象首地址指定偏移量位置上的值,作為期望值。

(2)取出獲取AtomicInteger對象偏移量上的值,判斷與期望值是否相等,相等就修改AtomicInteger在內(nèi)存偏移量上的值,不相等就返回false,重新執(zhí)行第一步操作,重新獲取內(nèi)存指定偏移量位置的值。

(3) 如果相等,則修改值并返回true。

注意:從1、2步可以看CAS機制實現(xiàn)的鎖是自旋鎖,如果線程一直無法獲取到鎖,則一直自旋,不會阻塞

CAS和syncronized的比較

CAS線程不會阻塞,線程一致自旋 syncronized會阻塞線程,會進行線程的上下文切換,會由用戶態(tài)切換到內(nèi)核態(tài),切換前需要保存用戶態(tài)的上下文,而內(nèi)核態(tài)恢復(fù)到用戶態(tài),又需要恢復(fù)保存的上下文,非常消耗資源。

CAS的缺點

(1)ABA問題 如果一個線程t1正修改共享變量的值A(chǔ),但還沒修改,此時另一個線程t2獲取到CPU時間片,將共享變量的值A(chǔ)修改為B,然后又修改為A,此時線程t1檢查發(fā)現(xiàn)共享變量的值沒有發(fā)生變化,但是實際上卻變化了。

解決辦法: 使用版本號,在變量前面追加上版本號,每次變量更新的時候把版本號加1,那么A-B-A 就會變成1A-2B-3A。從Java1.5開始JUC包里提供了一個類AtomicStampedReference來解決ABA問題。AtomicStampedReference類的compareAndSet方法作用是首先檢查當(dāng)前引用是否等于預(yù)期引用,并且當(dāng)前版本號是否等于預(yù)期版本號,如果全部相等,則以原子方式將該引用和該標(biāo)志的值設(shè)置為給定的更新值。

(2)循環(huán)時間長開銷會比較大:自旋重試時間,會給CPU帶來非常大的執(zhí)行開銷

(3)只能保證一個共享變量的原子操作,不能保證同時對多個變量的原子性操作 解決辦法: 從Java1.5開始JDK提供了AtomicReference類來保證引用對象之間的原子性,你可以把多個變量放在一個對象里來進行CAS操作

CAS使用注意事項

(1)CAS需要和volatile配合使用

CAS只能保證變量的原子性,不能保證變量的內(nèi)存可見性。CAS獲取共享變量的值時,需要和volatile配合使用,來保證共享變量的可見性

(2)CAS適用于并發(fā)量不高、多核CPU的情況

CPU多核情況下可以同時執(zhí)行,如果不合適就失敗。而并發(fā)量過高,會導(dǎo)致自旋重試耗費大量的CPU資源

到此這篇關(guān)于Java中的CAS鎖機制(無鎖、自旋鎖、樂觀鎖、輕量級鎖)詳解的文章就介紹到這了,更多相關(guān)CAS鎖機制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java使用單向鏈表解決數(shù)據(jù)存儲自定義排序問題

    java使用單向鏈表解決數(shù)據(jù)存儲自定義排序問題

    本文主要介紹了java使用單向鏈表解決數(shù)據(jù)存儲自定義排序問題,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Java文件與IO流操作原理詳細(xì)分析

    Java文件與IO流操作原理詳細(xì)分析

    在java中提供有對于文件操作系統(tǒng)的支持,這個支持在java.io.File類中進行了定義,也就是說在整個java.io包中File類是唯一一個與文件本身操作有關(guān)的類(創(chuàng)建,刪除,重命名)有關(guān)的類,而如果想要進行File類的操作,我們需要提供有完整的路徑支持,而后可以調(diào)用相應(yīng)的方法進行處理
    2022-09-09
  • 解決spring-boot使用logback的大坑

    解決spring-boot使用logback的大坑

    這篇文章主要介紹了解決spring-boot使用logback的大坑,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java使用modbus-master-tcp實現(xiàn)modbus tcp通訊

    Java使用modbus-master-tcp實現(xiàn)modbus tcp通訊

    這篇文章主要為大家詳細(xì)介紹了另外一種Java語言的modbux tcp通訊方案,那就是modbus-master-tcp,文中的示例代碼講解詳細(xì),需要的可以了解下
    2023-12-12
  • Java高效映射工具MapStruct的使用示例

    Java高效映射工具MapStruct的使用示例

    MapStruct 是一個 Java 注解處理器,用于在不同 Java Beans 或數(shù)據(jù)傳輸對象(DTOs)之間自動生成類型安全的映射代碼,這是一個編譯時映射框架,意味著它利用注解在編譯時生成代碼,本文將給大家介紹一下Java注解處理器MapStruct的使用示例,需要的朋友可以參考下
    2023-12-12
  • 使用Java實現(xiàn)讀取手機文件名稱

    使用Java實現(xiàn)讀取手機文件名稱

    這篇文章主要為大家詳細(xì)介紹了如何使用Java實現(xiàn)讀取手機文件名稱,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-03-03
  • SpringCloud?Function?SpEL注入漏洞分析及環(huán)境搭建

    SpringCloud?Function?SpEL注入漏洞分析及環(huán)境搭建

    SpringCloud 是一套分布式系統(tǒng)的解決方案,常見的還有阿里巴巴的Dubbo,F(xiàn)ass的底層實現(xiàn)就是函數(shù)式編程,SpringCloud Function 就是Spring提供的分布式函數(shù)式編程組件,下面給大家介紹下SpringCloud?Function?SpEL注入漏洞分析,感興趣的朋友一起看看吧
    2022-04-04
  • 詳解Spring Boot 使用Spring security 集成CAS

    詳解Spring Boot 使用Spring security 集成CAS

    本篇文章主要介紹了詳解Spring Boot 使用Spring security 集成CAS,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • Java中replace、replaceAll和replaceFirst函數(shù)的用法小結(jié)

    Java中replace、replaceAll和replaceFirst函數(shù)的用法小結(jié)

    相信會java的同學(xué)估計都用過replace、replaceAll、replaceFirst這三個函數(shù),可是,我們真的懂他們嗎?下面通過這篇文章大家再來好好學(xué)習(xí)學(xué)習(xí)下這幾個函數(shù)。
    2016-09-09
  • 解析Spring中@Controller@Service等線程安全問題

    解析Spring中@Controller@Service等線程安全問題

    這篇文章主要為大家介紹解析了Spring中@Controller@Service等線程的安全問題,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-03-03

最新評論