Java深入学习02:CAS 算法以及低层原理
参考文章:https://www.cnblogs.com/linkworld/p/7819270.html;已经描述很清晰
i++
的原子性问题
i++
的操作实际上分为三个步骤: "读-改-写";- 原子性: 就是"i++"的"读-改-写"是不可分割的三个步骤;
- 原子变量: JDK1.5 以后,
java.util.concurrent.atomic
包下,提供了常用的原子变量;- 原子变量中的值,使用
volatile
修饰,保证了内存可见性; - CAS(Compare-And-Swap) 算法保证数据的原子性;
- 原子变量中的值,使用
int i = 10; i = i++; // 此时, i=10 执行步骤: int temp = i; i = i + 1; i = temp; // 测试类 public class TestAtomicDemo{ public static void main(String[] args){ AtomicDemo ad = new AtomicDemo(); for(int i=0; i < 10; i++){ new Thread(ad).start(); } } } class AtomicDemo implements Runnable{ private int serialNumber = 0; public void run(){ try{ Thread.sleep(200); }catch(InterruptedException e){ } System.out.println(Thread.currentThread().getName() + ":" + getSerialNumber()); } public int getSerialNumber(){ return serialNumber++; } }
// 改进: 使用原子变量 class AtomicDemo implements Runnable{ private AtomicInteger serialNumber = new AtomicInteger(); public void run(){ try{ Thread.sleep(200); }catch(InterruptedException e){ } System.out.println(Thread.currentThread().getName()+":"+getSerialNumber()); } public int getSerialNumber(){ // 自增运算 return serialNumber.getAndIncrement(); } }
CAS 算法
- CAS(Compare-And-Swap) 算法是硬件对于并发的支持,针对多处理器操作而设计的处理器中的一种特殊指令,用于
管理对共享数据的并发访问; - CAS 是一种无锁的非阻塞算法的实现;
- CAS 包含了三个操作数:
- 需要读写的内存值: V
- 进行比较的预估值: A
- 拟写入的更新值: B
- 当且仅当 V == A 时, V = B, 否则,将不做任何操作;
// 模拟CAS 算法
class CompareAndSwap{
private int value;
// 获取内存值
public synchronized int get(){
return value;
}
// 无论更新成功与否,都返回修改之前的内存值
public synchronized int compareAndSwap(int expectedValue, int newValue){
// 获取旧值
int oldValue = value;
if(oldValue == expectedValue){
this.value = newValue;
}
// 返回修改之前的值
return oldValue;
}
// 判断是否设置成功
public synchronized boolean compareAndSet(int expectedValue, int newValue){
return expectedValue == compareAndSwap(expectedValue, newValue);
}
}
public class TestCompareAndSwap{
public static void main(String[] args){
final CopareAndSwap cas = new CompareAndSwap();
for(int i=0; i<10; i++){
// 创建10个线程,模拟多线程环境
new Thead(new Runnable(){
public void run(){
int expectedValue = cas.get();
boolean b = cas.compareAndSet(expectedValue, (int)(Math.random()*100));
System.out.println(b);
}
}).start();
}
}
}
CAS优点
1- 避免优先级倒置和死锁等危险,竞争比较便宜,协调发生在更细的粒度级别,允许更高程度的并行机制等。
CAS缺点
1- 循环时间长CPU开销很大;
2- 只能保证一个共享变量的原子性
3- 引出了ABA问题
CAS算法底层原理
我们以AtomicIntegerd 的getAndIncrement方法为例,进行简要分析。
##AtomicInteger类 private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long valueOffset;//AtomicInteger 对象 value 属性偏移地址 public final int getAndIncrement() { return unsafe.getAndAddInt(this, valueOffset, 1); } ##Unsafe类 public final int getAndAddInt(Object var1, long var2, int var4) { int var5; do { var5 = this.getIntVolatile(var1, var2); } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; } @CallerSensitive public static Unsafe getUnsafe() { Class var0 = Reflection.getCallerClass(); if (!VM.isSystemDomainLoader(var0.getClassLoader())) { throw new SecurityException("Unsafe"); } else { return theUnsafe; } } public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);