CAS
CAS即CompareAndSwap,比较并交换,是一种保证原子性的操作。有三个操作数,分别是内存地址,旧的预期值,和要替换的新值。
通过比较内存中的值是否和预期值相同,相同则将内存中的值和新值交换。
CAS存在的问题
- ABA。根据具体场景看是否会影响执行的结果。
- 自旋长时间消耗cpu资源
- 只能对一个共享变量操作
CAS可见性
这个其实是我想记录下来的。通过阅读《Java并发编程之美》,在看到原子操作这里,存在疑问,cas能够做到内存可见性吗?阅读了一些博客看到有的说能保证,但还是心存疑惑,于是写了段代码来验证。
public class Ex003 {
int flag=1;
static Unsafe unsafe;
static long fieldOffset;
static {
Class<Unsafe> unsafeClass = Unsafe.class;
try {
//通过反射获取unsafe
Field field = unsafeClass.getDeclaredField("theUnsafe");
field.setAccessible(true);
unsafe=(Unsafe) field.get(null);
fieldOffset = unsafe.objectFieldOffset(Ex003.class.getDeclaredField("flag"));
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
Ex003 ex003 = new Ex003();
new Thread(new Runnable() {
int i=0;
@Override
public void run() {
while (ex003.flag==1){
//flag变量声明为对象,防止值传递生成副本,保证cas操作的内存地址存的是flag对象
i++;
//println方法中包含同步代码块,会导致flag值受到synchronized的可见性的影响
//System.out.println(i);
}
}
}).start();
Thread.sleep(1000);
ex003.changFlag();
}
void changFlag(){
boolean b = unsafe.compareAndSwapInt(this, fieldOffset, 1, 0);
System.out.println(b+" "+this.flag);
}
}
执行结果是,在打印出"true 0"后,程序依然在运行。而将flag添加volatile修饰后,打印出语句后程序终止。
对于我的理解是:书上说cas的原子操作是由cpu级别的锁来实现的,而他的这个可见性应该是对于多个cpu之间能够保证修改了变量的值对其他cpu是可见的。
而我们常说的Java并发中的内存可见性指的是JMM的可见性,所以cas对共享变量的修改对其他线程是不可见的。
写在最后
关于可见性是我在准备记录cas这个点的时候的突发奇想,然后写下了我的思考于想法。如果大家有什么想法欢迎评论留言,一起探讨。