二、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