CAS算法
CAS(compare-and-swap)是一種硬件對併發的支持,針對多處理器操作而設計的處理器中的一種特殊指令,用於管理對共享數據的併發訪問。
CAS是一種無鎖非阻塞算法的實現。
CAS 包含了 3 個操作數:
需要讀寫的內存值V
進行比較的值A
擬寫入的新值B當且僅當V的值等於A時,CAS通過原子方式用新值更新V的值,否則不會執行任何操作。
CAS操作過程如下所示
CAS算法模擬
/**
* 模擬CAS算法
*
* Created by 吳海飛 on 2017-1-22.
*/
public class TestCompareAndSwap {
public static void main(String[] args){
final CompareAndSwap cas = new CompareAndSwap();
for (int i = 0; i < 10; i++ ){
new Thread(new Runnable() {
@Override
public void run() {
int expectValue = cas.getValue();
boolean b = cas.compareAndSet(expectValue, (int)(Math.random() * 101));
System.out.println(b);
}
}
).start();
}
}
}
class CompareAndSwap{
private int value;
//獲取內存值
public synchronized int getValue(){
return this.value;
}
//比較
public synchronized int compareAndSwap(int expectValue,int newValue){
int oldValue = this.value;
if(oldValue == expectValue){//如果期望值等於舊值
this.value = newValue;
}
return oldValue;
}
public synchronized boolean compareAndSet(int expectValue,int newValue){
return expectValue == compareAndSwap(expectValue, newValue);
}
}
原子變量
類的小工具包,支持在單個變量上解除鎖的線程安全編程。事實上,此包中的類可將 volatile 值、字段和數組元素的概念擴展到那些也提供原子條件更新操作的類。
類 AtomicBoolean、 AtomicInteger、 AtomicLong 和 AtomicReference 的實例各自提供對相應類型單個變量的訪問和更新。每個類也爲該類型提供適當的實用工具方法。
AtomicIntegerArray、 AtomicLongArray 和 AtomicReferenceArray 類進一步擴展了原子操作,對這些類型的數組提供了支持。這些類在爲其數組元素提供 volatile 訪問語義方面也引人注目,這對於普通數組來說是不受支持的。
核心方法: boolean compareAndSet(expectedValue, updateValue)
java.util.concurrent.atomic 包下提供了一些原子操作的常用類:
- AtomicBoolean 、 AtomicInteger 、 AtomicLong 、AtomicReference
- AtomicIntegerArray 、 AtomicLongArray
- AtomicMarkableReference
- AtomicReferenceArray
- AtomicStampedReference
原子變量使用Demo
import java.util.concurrent.atomic.AtomicInteger;
/**
*一、i++ 的原子性問題:i++ 的操作實際上分爲三個步驟“讀-改-寫”
* int i = 10;
* i = i++; //10
*
* int temp = i;
* i = i + 1;
* i = temp;
* 二、原子變量:在 java.util.concurrent.atomic 包下提供了一些原子變量。
* 1. volatile 保證內存可見性
* 2. CAS(Compare-And-Swap) 算法保證數據變量的原子性
* CAS 算法是硬件對於併發操作的支持
* CAS 包含了三個操作數:
* ①內存值 V
* ②預估值 A
* ③更新值 B
* 當且僅當 V == A 時, V = B; 否則,不會執行任何操作。
*/
public class AtomicDemo {
public static void main(String[] args) {
AtomicData ad = new AtomicData();
for (int i = 0; i < 10; i++) {
new Thread(ad).start();
}
}
}
class AtomicData implements Runnable{
//初始化原子變量
private AtomicInteger atomicData = new AtomicInteger(0);
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getAtomicData());
}
public int getAtomicData(){
return atomicData.getAndIncrement();//相當於atomicData++
}
}