Java多線程-2-CAS

二、CAS

1、概念

CAS(compareAndSwap),比較並交換

CAS操作需要輸入兩個值,一箇舊值(操作前的值),一個新值(要操作的值)。在操作期間首先比較舊值有沒有發生改變,如果沒有變化,則交換成新值,否則不交換

主要用於java.util.concurrent包下的多個類(lock、atomic)的底層實現,核心類是sun.misc.Unsafe,類裏的方法大都是native方法,因爲它調用的是操作系統底層的彙編指令

2、Java實現原子操作

除了使用鎖以外,還可以使用自旋 + CAS

自旋是爲了減少線程上下文切換的開銷

3、CAS實現原子操作的三大問題

【1】ABA問題

問題描述:因爲CAS操作的時候,需要進行比較。如果舊值被修改多次,而恰好最後一次更新的值是本次比較的舊值,這樣就會把本不應該更新的情況,給更新了

解決辦法:使用版本號來追加判斷。不僅比較值是否相同,還要比較版本號是否符合邏輯

【2】自旋時間長導致開銷大

問題描述:如果CAS操作一直不成功,就會導致自旋時間過長,這樣就給CPU帶來非常大的執行開銷(CPU使用率提高)

解決辦法:如果JVM能支持處理器提供的pause指令,那麼效率會有一定的提升。睡一會兒

【3】只能保證一個共享變量的原子操作

問題描述:CAS操作同一時間,只能比較一個值

解決辦法:加鎖。或者把多個共享變量合併成一個共享變量來操作,比如使用java.util.concurrent.atomic.AtomicReference

4、java.util.concurrent.atomic相關類

【1】AtomicInteger

AtomicInteger atomicInteger = new AtomicInteger(10);
boolean compareAndSet = atomicInteger.compareAndSet(10, 20);
System.out.println(compareAndSet); // true
System.out.println(atomicInteger.get()); // 20

System.out.println(atomicInteger.incrementAndGet()); // 21
System.out.println(atomicInteger.decrementAndGet()); // 20

【2】AtomicReference

Object obj1 = new Object();
System.out.println("obj1:" + obj1);

AtomicReference<Object> atomicReference = new AtomicReference<Object>(obj1);

Object obj2 = new Object();
System.out.println("obj2:" + obj2);

Object getAndSet = atomicReference.getAndSet(obj2);
System.out.println("舊值:" + getAndSet); // obj1
System.out.println("新值:" + atomicReference.get()); // obj2

【3】AtomicStampedReference

Object obj1 = new Object();
int stamp = 1;
AtomicStampedReference<Object> atomicStampedReference = new AtomicStampedReference<Object>(obj1, stamp);

Object obj2 = new Object();
System.out.println("obj2:" + obj2);

stamp = 2;
boolean compareAndSet = atomicStampedReference.compareAndSet(obj1, obj2, 1, stamp);
System.out.println(compareAndSet); // true
System.out.println(atomicStampedReference.getReference()); // obj2
System.out.println(atomicStampedReference.getStamp()); // 2
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章