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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

java 线程aba,JAVA中CAS-ABA的问题解决方案AtomicStampedReference

發布時間:2025/3/20 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 线程aba,JAVA中CAS-ABA的问题解决方案AtomicStampedReference 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

了解CAS(Compare-And-Swap)

CAS即對比交換,它在保證數據原子性的前提下盡可能的減少了鎖的使用,很多編程語言或者系統實現上都大量的使用了CAS。

JAVA中CAS的實現

JAVA中的cas主要使用的是Unsafe方法,Unsafe的CAS操作主要是基于硬件平臺的匯編指令,目前的處理器基本都支持CAS,只不過不同的廠家的實現不一樣罷了。

Unsafe提供了三個方法用于CAS操作,分別是

public final native boolean compareAndSwapObject(Object value, long valueOffset, Object expect, Object update);

public final native boolean compareAndSwapInt(Object value, long valueOffset, int expect, int update);

public final native boolean compareAndSwapLong(Object value, long valueOffset, long expect, long update);

復制代碼

value 表示 需要操作的對象

valueOffset 表示 對象(value)的地址的偏移量(通過Unsafe.objectFieldOffset(Field valueField)獲取)

expect 表示更新時value的期待值

update 表示將要更新的值

具體過程為每次在執行CAS操作時,線程會根據valueOffset去內存中獲取當前值去跟expect的值做對比如果一致則修改并返回true,如果不一致說明有別的線程也在修改此對象的值,則返回false

Unsafe類中compareAndSwapInt的具體實現:

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))

UnsafeWrapper("Unsafe_CompareAndSwapInt");

oop p = JNIHandles::resolve(obj);

jint* addr = (jint *) index_oop_from_field_offset_long(p, offset);

return (jint)(Atomic::cmpxchg(x, addr, e)) == e;

UNSAFE_END

復制代碼

ABA問題

線程1準備用CAS修改變量值A,在此之前,其它線程將變量的值由A替換為B,又由B替換為A,然后線程1執行CAS時發現變量的值仍然為A,所以CAS成功。但實際上這時的現場已經和最初不同了。

aba.png

例子

public static AtomicInteger a = new AtomicInteger(1);

public static void main(String[] args){

Thread main = new Thread(() -> {

System.out.println("操作線程" + Thread.currentThread() +",初始值 = " + a); //定義變量 a = 1

try {

Thread.sleep(1000); //等待1秒 ,以便讓干擾線程執行

} catch (InterruptedException e) {

e.printStackTrace();

}

boolean isCASSuccess = a.compareAndSet(1,2); // CAS操作

System.out.println("操作線程" + Thread.currentThread() +",CAS操作結果: " + isCASSuccess);

},"主操作線程");

Thread other = new Thread(() -> {

a.incrementAndGet(); // a 加 1, a + 1 = 1 + 1 = 2

System.out.println("操作線程" + Thread.currentThread() +",【increment】 ,值 = "+ a);

a.decrementAndGet(); // a 減 1, a - 1 = 2 - 1 = 1

System.out.println("操作線程" + Thread.currentThread() +",【decrement】 ,值 = "+ a);

},"干擾線程");

main.start();

other.start();

}

復制代碼

// 輸出

> 操作線程Thread[主操作線程,5,main],初始值 = 1

> 操作線程Thread[干擾線程,5,main],【increment】 ,值 = 2

> 操作線程Thread[干擾線程,5,main],【decrement】 ,值 = 1

> 操作線程Thread[主操作線程,5,main],CAS操作結果: true

復制代碼

解決ABA方案

思路

解決ABA最簡單的方案就是給值加一個修改版本號,每次值變化,都會修改它版本號,CAS操作時都對比此版本號。

aba_2.png

JAVA中ABA中解決方案(AtomicStampedReference)

AtomicStampedReference主要維護包含一個對象引用以及一個可以自動更新的整數"stamp"的pair對象來解決ABA問題。

//關鍵代碼

public class AtomicStampedReference {

private static class Pair {

final T reference; //維護對象引用

final int stamp; //用于標志版本

private Pair(T reference, int stamp) {

this.reference = reference;

this.stamp = stamp;

}

static Pair of(T reference, int stamp) {

return new Pair(reference, stamp);

}

}

private volatile Pair pair;

....

/**

* expectedReference :更新之前的原始值

* newReference : 將要更新的新值

* expectedStamp : 期待更新的標志版本

* newStamp : 將要更新的標志版本

*/

public boolean compareAndSet(V expectedReference,

V newReference,

int expectedStamp,

int newStamp) {

Pair current = pair; //獲取當前pair

return

expectedReference == current.reference && //原始值等于當前pair的值引用,說明值未變化

expectedStamp == current.stamp && // 原始標記版本等于當前pair的標記版本,說明標記未變化

((newReference == current.reference &&

newStamp == current.stamp) || // 將要更新的值和標記都沒有變化

casPair(current, Pair.of(newReference, newStamp))); // cas 更新pair

}

}

復制代碼

例子

private static AtomicStampedReference atomicStampedRef =

new AtomicStampedReference<>(1, 0);

public static void main(String[] args){

Thread main = new Thread(() -> {

System.out.println("操作線程" + Thread.currentThread() +",初始值 a = " + atomicStampedRef.getReference());

int stamp = atomicStampedRef.getStamp(); //獲取當前標識別

try {

Thread.sleep(1000); //等待1秒 ,以便讓干擾線程執行

} catch (InterruptedException e) {

e.printStackTrace();

}

boolean isCASSuccess = atomicStampedRef.compareAndSet(1,2,stamp,stamp +1); //此時expectedReference未發生改變,但是stamp已經被修改了,所以CAS失敗

System.out.println("操作線程" + Thread.currentThread() +",CAS操作結果: " + isCASSuccess);

},"主操作線程");

Thread other = new Thread(() -> {

atomicStampedRef.compareAndSet(1,2,atomicStampedRef.getStamp(),atomicStampedRef.getStamp() +1);

System.out.println("操作線程" + Thread.currentThread() +",【increment】 ,值 = "+ atomicStampedRef.getReference());

atomicStampedRef.compareAndSet(2,1,atomicStampedRef.getStamp(),atomicStampedRef.getStamp() +1);

System.out.println("操作線程" + Thread.currentThread() +",【decrement】 ,值 = "+ atomicStampedRef.getReference());

},"干擾線程");

main.start();

other.start();

}

復制代碼

// 輸出

> 操作線程Thread[干擾線程,5,main],【increment】 ,值 = 2

> 操作線程Thread[干擾線程,5,main],【decrement】 ,值 = 1

> 操作線程Thread[主操作線程,5,main],初始值 a = 1

> 操作線程Thread[主操作線程,5,main],CAS操作結果: true

復制代碼

總結

以上是生活随笔為你收集整理的java 线程aba,JAVA中CAS-ABA的问题解决方案AtomicStampedReference的全部內容,希望文章能夠幫你解決所遇到的問題。

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