Java CAS简析
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java CAS简析相关的知识,希望对你有一定的参考价值。
什么是CAS
CAS:Compare and Swap,它是一种原子操作,什么是原子操作,可以在多线程编程中实现数据交换而不被打断。是用来更新变量的,当多个线程使用CAS来更新变量时,只有一个线程可以更新变量的值,其他线程都会失败,失败的线程不回被挂起,而是重试直到成功为止。
CAS实现方式,有三个变量,内存值V,处理器缓存(预期值)A,更新值B。比较内存值与预期值,相等则说明没有其他线程操作共享数据,则更新内存值为B;不等说明共享数据V已经被其他线程改动了,放弃更新操作,重新load共享数据,重试之前操作。
CAS的运用
乐观锁:其实现机制是基于CAS的,每次不加锁,假设没有冲突完成操作,如果有冲突,充实知道成功为止。
Java原子类:AtomicInteger等
源码分析
一起看一下AtomicInteger是怎么实现free-lock的。
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
private volatile int value;
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
value 是用volatile 修饰的,可以保证get与set的原子性,但无法保证incrementAndGet读写改的复合操作。其实际调用的方法是unsafe的getAndAddInt
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;
}
unsafe 通过JNI调用C++ 的一些方法,首先是根据内存地址获取到value的值,然后调用compareAndSwapInt,true:更新变量成功,false:不成功。compareAndSwapInt经过汇编后最主要的是CMPXCHG指令,该指令是 操作系统级别的原子操作。所以,抛开C++与汇编源码,可以理解为Java运用了os的原子性来实现无锁编程。
那操作系统是如何保证CAS原子性呢?在写操作前会有一个Lock前缀,它会引发两件事情。
- 将当前处理器缓存行的数据写回到内存行。
- 这个写缓存操作会使其他CPU里的缓存了该内存地址的数据无效。
使用总线锁保证原子性:
处理器提供一个Lock# 信号,当处理器在总线上输出此信号时,其他处理的请求将被阻塞,改处理器就可以独占共享内存。
缺点:对于多核(32,64),其中一个cpu锁住了总线,其他所有核与内存之间的通信都被锁住了,开销太大。
使用缓存锁保证原子性
直接修改内存,缓存一致性机制来保障操作的原子性。
ABA 问题
一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有变化,其实却变化了,解决思路是加上版本号。
参考:
以上是关于Java CAS简析的主要内容,如果未能解决你的问题,请参考以下文章