并發程式設計–原子操作CAS
1.預備概念
CAS:(compared and sweep)比較後進行交換,是一種樂觀鎖的設計思想。
synchronized:是以一種基于悲觀鎖的實作。
原子操作:不會被線程排程機制打斷的操作;這種操作一旦開始,就一直運作到結束,中間不會有任何上下文切換,在x86 平台上,CPU提供了在指令執行期間對總線加鎖的手段,需要硬體支援。
2.CAS原理
一.實作原理:
流程
比較後進行交換,當更新值的時候,帶上舊值,如果舊值和目前變量的值相等,那就認為該資料沒有被更其他線程操作過,再把新值指派給該變量。
- 第一步目前線程通過舊值經過計算得到新值。
- compare記憶體中變量值和舊值,如果相等進入下一步。
- 舊值swap為新值。
帶來的問題:
- ABA問題:利用CAS確定原子性,會帶來ABA問題,是以常見的CAS一般帶有版本号來确定是否有ABA問題。***cas(記憶體位址,舊值,新值)***。
- 開銷問題:當舊值和記憶體中的值不相等,重新進入一次計算,可能導緻死循環。
- 效率問題:一次CAS隻能操作一個變量,當有多個變量需要組合更改。
利用CAS實作的原子操作類
更新基本類型的:AtomicBoolean AtomicInteger AtomicLong
更新數組的:AtomicIntegerArray AtomicLongArray
更新引用類型的:AtomicReference AtomicMarkableReference.
AtomicIntegerArray 測試:
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicIntegerArray;
public class AtomicIntegerTest {
public static void main(String[] args) {
int [] integers = new int[]{1,2};
AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(integers);
atomicIntegerArray.set(0,3);
System.out.println(atomicIntegerArray.get(0));
System.out.println(integers[0]);
}
}
運作結果:
3
1
~~~java
AtomicMarkedReference:通過boolean是否修改的方式保持原子性。
AtomicStampReference:通過版本戳的形式去保持原子更新,更新的版本可控。
測試代碼:AtomicMarkedReferenceTest
package cn.enjoyedu.ch3;
import java.util.concurrent.atomic.AtomicMarkableReference;
import java.util.concurrent.atomic.AtomicStampedReference;
public class AtomicStampReferenceTest {
public static void main(String[] args) throws InterruptedException {
AtomicReferenceTest.UserInfo userInfo = new AtomicReferenceTest.UserInfo("james", 20);
//聲明一個引用
// AtomicStampedReference<AtomicReferenceTest.UserInfo> atomicStampedReference = new AtomicStampedReference<AtomicReferenceTest.UserInfo>(userInfo,0);
AtomicMarkableReference<AtomicReferenceTest.UserInfo> atomicStampedReference = new AtomicMarkableReference<AtomicReferenceTest.UserInfo>(userInfo,false);
//聲明兩個線程去修改
Thread thread = new Thread(new ThreadModify1(atomicStampedReference));
thread.start();
thread.join();
Thread thread2 = new Thread(new ThreadModify2(atomicStampedReference));
thread2.start();
}
static class ThreadModify1 extends Thread{
AtomicMarkableReference<AtomicReferenceTest.UserInfo> atomicStampedReference ;
public ThreadModify1(AtomicMarkableReference<AtomicReferenceTest.UserInfo> atomicStampedReference){
this.atomicStampedReference = atomicStampedReference;
}
@Override
public void run() {
//擷取值和版本号
AtomicReferenceTest.UserInfo userInfo = atomicStampedReference.getReference();
//stamp
boolean stamp = atomicStampedReference.isMarked();
AtomicReferenceTest.UserInfo deer = new AtomicReferenceTest.UserInfo("deer", 100);
boolean b = atomicStampedReference.compareAndSet(userInfo, deer, stamp, false);
System.out.println(currentThread().getName()+b);
}
}
static class ThreadModify2 extends Thread{
AtomicMarkableReference<AtomicReferenceTest.UserInfo> atomicStampedReference ;
public ThreadModify2(AtomicMarkableReference<AtomicReferenceTest.UserInfo> atomicStampedReference){
this.atomicStampedReference = atomicStampedReference;
}
@Override
public void run() {
//擷取值和版本号
AtomicReferenceTest.UserInfo userInfo = atomicStampedReference.getReference();
//stamp
boolean stamp = atomicStampedReference.isMarked();
AtomicReferenceTest.UserInfo deer = new AtomicReferenceTest.UserInfo("deer", 100);
boolean b = atomicStampedReference.compareAndSet(userInfo, deer, stamp, false);
System.out.println(currentThread().getName()+b);
}
}
}
運作結果:
Thread-1true
Thread-3false
測試代碼:AtomicStampReferenceTest
import java.util.concurrent.atomic.AtomicMarkableReference;
import java.util.concurrent.atomic.AtomicStampedReference;
public class AtomicStampReferenceTest {
public static void main(String[] args) throws InterruptedException {
AtomicReferenceTest.UserInfo userInfo = new AtomicReferenceTest.UserInfo("james", 20);
//聲明一個引用
AtomicStampedReference<AtomicReferenceTest.UserInfo> atomicStampedReference = new AtomicStampedReference<AtomicReferenceTest.UserInfo>(userInfo,0);
//聲明兩個線程去修改
Thread thread = new Thread(new ThreadModify1(atomicStampedReference));
thread.start();
thread.join();
Thread thread2 = new Thread(new ThreadModify2(atomicStampedReference));
thread2.start();
}
static class ThreadModify1 extends Thread{
AtomicStampedReference<AtomicReferenceTest.UserInfo> atomicStampedReference ;
public ThreadModify1(AtomicStampedReference<AtomicReferenceTest.UserInfo> atomicStampedReference){
this.atomicStampedReference = atomicStampedReference;
}
@Override
public void run() {
//擷取值和版本号
AtomicReferenceTest.UserInfo userInfo = atomicStampedReference.getReference();
//stamp
int stamp = atomicStampedReference.getStamp();
AtomicReferenceTest.UserInfo deer = new AtomicReferenceTest.UserInfo("deer", 100);
boolean b = atomicStampedReference.compareAndSet(userInfo, deer, stamp, stamp + 2);
System.out.println(currentThread().getName()+b);
}
}
static class ThreadModify2 extends Thread{
AtomicStampedReference<AtomicReferenceTest.UserInfo> atomicStampedReference ;
public ThreadModify2(AtomicStampedReference<AtomicReferenceTest.UserInfo> atomicStampedReference){
this.atomicStampedReference = atomicStampedReference;
}
@Override
public void run() {
//擷取值和版本号
AtomicReferenceTest.UserInfo userInfo = atomicStampedReference.getReference();
//stamp
int stamp = 0;
//atomicStampedReference.getStamp();
AtomicReferenceTest.UserInfo deer = new AtomicReferenceTest.UserInfo("deer", 100);
boolean b= atomicStampedReference.compareAndSet(userInfo,deer,stamp,stamp+2);
System.out.println(currentThread().getName()+b);
}
}
}
運作結果:
Thread-1true
Thread-3false