日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁 > 科技  > 軟件

美團(tuán)一面:什么是CAS?有什么優(yōu)缺點(diǎn)?我說我知道AtomicInteger

來源: 責(zé)編: 時間:2024-04-22 09:16:12 180觀看
導(dǎo)讀引言傳統(tǒng)的并發(fā)控制手段,如使用synchronized關(guān)鍵字或者ReentrantLock等互斥鎖機(jī)制,雖然能夠有效防止資源的競爭沖突,但也可能帶來額外的性能開銷,如上下文切換、鎖競爭導(dǎo)致的線程阻塞等。而此時就出現(xiàn)了一種樂觀鎖的策略,

引言

傳統(tǒng)的并發(fā)控制手段,如使用synchronized關(guān)鍵字或者ReentrantLock等互斥鎖機(jī)制,雖然能夠有效防止資源的競爭沖突,但也可能帶來額外的性能開銷,如上下文切換、鎖競爭導(dǎo)致的線程阻塞等。而此時就出現(xiàn)了一種樂觀鎖的策略,以其非阻塞、輕量級的特點(diǎn),在某些場合下能更好地提升并發(fā)性能,其中最為關(guān)鍵的技術(shù)便是Compare And Swap(簡稱CAS)。lmX28資訊網(wǎng)——每日最新資訊28at.com

CAS是一種無鎖算法,它在硬件級別提供了原子性的條件更新操作,允許線程在不加鎖的情況下實(shí)現(xiàn)對共享變量的修改。在Java中,CAS機(jī)制被廣泛應(yīng)用于java.util.concurrent.atomic包下的原子類以及高級并發(fā)工具類如AbstractQueuedSynchronizer(AQS)的實(shí)現(xiàn)中。lmX28資訊網(wǎng)——每日最新資訊28at.com

CAS的基本概念與原理

CAS是一種原子指令,常用于多線程環(huán)境中的無鎖算法。CAS操作包含三個基本操作數(shù):內(nèi)存位置、期望值和新值。在執(zhí)行CAS操作時,計算機(jī)會檢查內(nèi)存位置當(dāng)前是否存放著期望值,如果是,則將內(nèi)存位置的值更新為新值;若不是,則不做任何修改,保持原有值不變,并返回當(dāng)前內(nèi)存位置的實(shí)際值。lmX28資訊網(wǎng)——每日最新資訊28at.com

在Java中,CAS機(jī)制被封裝在jdk.internal.misc.Unsafe類中,盡管這個類并不建議在普通應(yīng)用程序中直接使用,但它是構(gòu)建更高層次并發(fā)工具的基礎(chǔ),例如java.util.concurrent.atomic包下的原子類如AtomicInteger、AtomicLong等。這些原子類通過JNI調(diào)用底層硬件提供的CAS指令,從而在Java層面上實(shí)現(xiàn)了無鎖并發(fā)操作。lmX28資訊網(wǎng)——每日最新資訊28at.com

這里指的注意的是,在JDK1.9之前CAS機(jī)制被封裝在sun.misc.Unsafe類中,在JDK1.9之后就使用了 jdk.internal.misc.Unsafe。這點(diǎn)由java.util.concurrent.atomic包下的原子類可以看出來。而sun.misc.Unsafe被許多第三方庫所使用。lmX28資訊網(wǎng)——每日最新資訊28at.com

CAS實(shí)現(xiàn)原理

在Java中,雖然Java語言本身并未直接提供CAS這樣的原子指令,但是Java可以通過JNI調(diào)用本地方法來利用硬件級別的原子指令實(shí)現(xiàn)CAS操作。在Java的標(biāo)準(zhǔn)庫中,特別是jdk.internal.misc.Unsafe類提供了一系列compareAndSwapXXX方法,這些方法底層確實(shí)是通過C++編寫的內(nèi)聯(lián)匯編來調(diào)用對應(yīng)CPU架構(gòu)的cmpxchg指令,從而實(shí)現(xiàn)原子性的比較和交換操作。lmX28資訊網(wǎng)——每日最新資訊28at.com

cmpxchg指令是多數(shù)現(xiàn)代CPU支持的原子指令,它能在多線程環(huán)境下確保一次比較和交換操作的原子性,有效解決了多線程環(huán)境下數(shù)據(jù)競爭的問題,避免了數(shù)據(jù)不一致的情況。例如,在更新一個共享變量時,如果期望值與當(dāng)前值相匹配,則原子性地更新為新值,否則不進(jìn)行更新操作,這樣就能在無鎖的情況下實(shí)現(xiàn)對共享資源的安全訪問。 我們以java.util.concurrent.atomic包下的AtomicInteger為例,分析其compareAndSet方法。lmX28資訊網(wǎng)——每日最新資訊28at.com

public class AtomicInteger extends Number implements java.io.Serializable {    private static final long serialVersionUID = 6214790243416807050L;    //由這里可以看出來,依賴jdk.internal.misc.Unsafe實(shí)現(xiàn)的    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();    private static final long VALUE = U.objectFieldOffset(AtomicInteger.class, "value");    private volatile int value;    public final boolean compareAndSet(int expectedValue, int newValue) {         // 調(diào)用 jdk.internal.misc.Unsafe的compareAndSetInt方法        return U.compareAndSetInt(this, VALUE, expectedValue, newValue);      }}

Unsafe中的compareAndSetInt使用了@HotSpotIntrinsicCandidate注解修飾,@HotSpotIntrinsicCandidate注解是Java HotSpot虛擬機(jī)(JVM)的一個特性注解,它表明標(biāo)注的方法有可能會被HotSpot JVM識別為“內(nèi)聯(lián)候選”,當(dāng)JVM發(fā)現(xiàn)有方法被標(biāo)記為內(nèi)聯(lián)候選時,會嘗試?yán)玫讓佑布峁┑脑又噶睿ū热鏲mpxchg指令)直接替換掉原本的Java方法調(diào)用,從而在運(yùn)行時獲得更好的性能。lmX28資訊網(wǎng)——每日最新資訊28at.com

public final class Unsafe {    @HotSpotIntrinsicCandidate      public final native boolean compareAndSetInt(Object o, long offset,                                                   int expected,                                                   int x);}

compareAndSetInt這個方法我們可以從openjdk的hotspot源碼(位置:hotspot/src/share/vm/prims/unsafe.cpp)中可以找到:lmX28資訊網(wǎng)——每日最新資訊28at.com

{CC "compareAndSetObject",CC "(" OBJ "J" OBJ "" OBJ ")Z", FN_PTR(Unsafe_CompareAndSetObject)},{CC "compareAndSetInt", CC "(" OBJ "J""I""I"")Z", FN_PTR(Unsafe_CompareAndSetInt)},{CC "compareAndSetLong", CC "(" OBJ "J""J""J"")Z", FN_PTR(Unsafe_CompareAndSetLong)},{CC "compareAndExchangeObject", CC "(" OBJ "J" OBJ "" OBJ ")" OBJ, FN_PTR(Unsafe_CompareAndExchangeObject)},{CC "compareAndExchangeInt", CC "(" OBJ "J""I""I"")I", FN_PTR(Unsafe_CompareAndExchangeInt)},{CC "compareAndExchangeLong", CC "(" OBJ "J""J""J"")J", FN_PTR(Unsafe_CompareAndExchangeLong)},

關(guān)于openjdk的源碼,本文源碼版本為1.9,如需要該版本源碼或者其他版本下載方法,請關(guān)注本公眾號【碼農(nóng)Academy】后,后臺回復(fù)【openjdk】獲取lmX28資訊網(wǎng)——每日最新資訊28at.com

而hostspot中的Unsafe_CompareAndSetInt函數(shù)會統(tǒng)一調(diào)用Atomic的cmpxchg函數(shù):lmX28資訊網(wǎng)——每日最新資訊28at.com

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSetInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x)) {oop p = JNIHandles::resolve(obj);jint* addr = (jint *)index_oop_from_field_offset_long(p, offset);// 統(tǒng)一調(diào)用Atomic的cmpxchg函數(shù)return (jint)(Atomic::cmpxchg(x, addr, e)) == e;} UNSAFE_END

而Atomic的cmpxchg函數(shù)源碼(位置:hotspot/src/share/vm/runtime/atomic.hpp)如下:lmX28資訊網(wǎng)——每日最新資訊28at.com

/***這是按字節(jié)大小進(jìn)行的`cmpxchg`操作的默認(rèn)實(shí)現(xiàn)。它使用按整數(shù)大小進(jìn)行的`cmpxchg`來模擬按字節(jié)大小進(jìn)行的`cmpxchg`。不同的平臺可以通過定義自己的內(nèi)聯(lián)定義以及定義`VM_HAS_SPECIALIZED_CMPXCHG_BYTE`來覆蓋這個默認(rèn)實(shí)現(xiàn)。這將導(dǎo)致使用特定于平臺的實(shí)現(xiàn)而不是默認(rèn)實(shí)現(xiàn)。*  exchange_value:要交換的新值。*  dest:指向目標(biāo)字節(jié)的指針。*  compare_value:要比較的值。*  order:內(nèi)存順序。*/inline jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest,                             jbyte compare_value, cmpxchg_memory_order order) {  STATIC_ASSERT(sizeof(jbyte) == 1);  volatile jint* dest_int =      static_cast<volatile jint*>(align_ptr_down(dest, sizeof(jint)));  size_t offset = pointer_delta(dest, dest_int, 1);  // 獲取當(dāng)前整數(shù)大小的值,并將其轉(zhuǎn)換為字節(jié)數(shù)組。  jint cur = *dest_int;  jbyte* cur_as_bytes = reinterpret_cast<jbyte*>(&cur);  // 設(shè)置當(dāng)前整數(shù)中對應(yīng)字節(jié)的值為compare_value。這確保了如果初始的整數(shù)值不是我們要找的值,那么第一次的cmpxchg操作會失敗。  cur_as_bytes[offset] = compare_value;  // 在循環(huán)中,不斷嘗試更新目標(biāo)字節(jié)的值。  do {    // new_val    jint new_value = cur;    // 復(fù)制當(dāng)前整數(shù)值,并設(shè)置其中對應(yīng)字節(jié)的值為exchange_value。    reinterpret_cast<jbyte*>(&new_value)[offset] = exchange_value;    // 嘗試使用新的整數(shù)值替換目標(biāo)整數(shù)。    jint res = cmpxchg(new_value, dest_int, cur, order);    if (res == cur) break; // 如果返回值與原始整數(shù)值相同,說明操作成功。    // 更新當(dāng)前整數(shù)值為cmpxchg操作的結(jié)果。    cur = res;    // 如果目標(biāo)字節(jié)的值仍然是我們之前設(shè)置的值,那么繼續(xù)循環(huán)并再次嘗試。  } while (cur_as_bytes[offset] == compare_value);  // 返回更新后的字節(jié)值  return cur_as_bytes[offset];}

而由cmpxchg函數(shù)中的do...while我們也可以看出,當(dāng)多個線程同時嘗試更新同一內(nèi)存位置,且它們的期望值相同但只有一個線程能夠成功更新時,其他線程的CAS操作會失敗。對于失敗的線程,常見的做法是采用自旋鎖的形式,即循環(huán)重試直到成功為止。這種方式在低競爭或短時間窗口內(nèi)的并發(fā)更新時,相比于傳統(tǒng)的鎖機(jī)制,它避免了線程的阻塞和喚醒帶來的開銷,所以它的性能會更優(yōu)。lmX28資訊網(wǎng)——每日最新資訊28at.com

Java中的CAS實(shí)現(xiàn)與API

在Java中,CAS操作的實(shí)現(xiàn)主要依賴于兩個關(guān)鍵組件:sun.misc.Unsafe類、jdk.internal.misc.Unsafe類以及java.util.concurrent.atomic包下的原子類。盡管Unsafe類提供了對底層硬件原子操作的直接訪問,但由于其API是非公開且不穩(wěn)定的,所以在常規(guī)開發(fā)中并不推薦直接使用。Java標(biāo)準(zhǔn)庫提供了豐富的原子類,它們是基于Unsafe封裝的安全、便捷的CAS操作實(shí)現(xiàn)。lmX28資訊網(wǎng)——每日最新資訊28at.com

java.util.concurrent.atomic包

Java標(biāo)準(zhǔn)庫中的atomic包為開發(fā)者提供了許多原子類,如AtomicInteger、AtomicLong、AtomicReference等,它們均內(nèi)置了CAS操作邏輯,使得我們可以在更高的抽象層級上進(jìn)行無鎖并發(fā)編程。lmX28資訊網(wǎng)——每日最新資訊28at.com

lmX28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片lmX28資訊網(wǎng)——每日最新資訊28at.com

而對于這個問題,其實(shí)也很好解決,我們給這個數(shù)據(jù)加上一個時間戳或者版本號(樂觀鎖概念)。即每次不僅比較值,還會比較版本。比如上述示例,初始時str的值的版本是1,然后線程2操作后值變成B,而對應(yīng)版本變成了2,然后線程3操作后值變成了A,版本變成了3,而對于線程2來說,雖然值還是A,但是版本號變了,所以線程2依然會執(zhí)行替換的操作。lmX28資訊網(wǎng)——每日最新資訊28at.com

Java的原子類就提供了類似的實(shí)現(xiàn),如AtomicStampedReference和AtomicMarkableReference引入了附加的標(biāo)記位或版本號,以便區(qū)分不同的修改序列。lmX28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片lmX28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片lmX28資訊網(wǎng)——每日最新資訊28at.com

總結(jié)

Java中的CAS原理及其在并發(fā)編程中的應(yīng)用是一項(xiàng)非常重要的技術(shù)。CAS利用CPU硬件提供的原子指令,實(shí)現(xiàn)了在無鎖環(huán)境下的高效并發(fā)控制,避免了傳統(tǒng)鎖機(jī)制帶來的上下文切換和線程阻塞開銷。Java通過JNI接口調(diào)用底層的CAS指令,封裝在jdk.internal.misc類和java.util.concurrent.atomic包下的原子類中,為我們提供了簡潔易用的API來實(shí)現(xiàn)無鎖編程。lmX28資訊網(wǎng)——每日最新資訊28at.com

CAS在帶來并發(fā)性能提升的同時,也可能引發(fā)循環(huán)開銷過大、ABA問題等問題。針對這些問題,Java提供了如LongAdder、AtomicStampedReference和AtomicMarkableReference等工具類來解決ABA問題,同時也通過自適應(yīng)自旋、適時放棄自旋轉(zhuǎn)而進(jìn)入阻塞等待等方式降低循環(huán)開銷。lmX28資訊網(wǎng)——每日最新資訊28at.com

理解和熟練掌握CAS原理及其在Java中的應(yīng)用,有助于我們在開發(fā)高性能并發(fā)程序時作出更明智的選擇,既能提高系統(tǒng)并發(fā)性能,又能保證數(shù)據(jù)的正確性和一致性。lmX28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-84469-0.html美團(tuán)一面:什么是CAS?有什么優(yōu)缺點(diǎn)?我說我知道AtomicInteger

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 在前端中,什么是幽靈依賴?

下一篇: 如何做配置鏈接的質(zhì)量保障?看這篇就對了

標(biāo)簽:
  • 熱門焦點(diǎn)
Top 主站蜘蛛池模板: 临颍县| 马边| 盖州市| 罗平县| 滦南县| 利津县| 察隅县| 潞西市| 安龙县| 泰宁县| 寿光市| 凤凰县| 盐城市| 永平县| 松原市| 双流县| 长春市| 镇雄县| 东阿县| 宜川县| 滨海县| 莱阳市| 抚州市| 延安市| 邯郸市| 元江| 博湖县| 右玉县| 清水河县| 屏南县| 开封市| 石台县| 绍兴县| 沙湾县| 大余县| 阿尔山市| 平陆县| 康定县| 营口市| 新郑市| 徐州市|