11、CAS原理与实现:
1、定义:
比较和交换(Conmpare And Swap,简称CAS)是用于实现多线程同步的原子指令。
JAVA中的CAS操作都是通过sun包下Unsafe类实现,而Unsafe类中的方法都是native方,
native方法的实现位于unsafe.cpp
源码流程如下:
java中方法(以AtomicInteger为例):
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
//对象o中offset偏移位置的值等于期望值(expected),
//就将该offset处的值更新为x,当更新成功时,返回true,
//native标记的方法在C++底层实现
public final native boolean compareAndSwapInt(Object o, long offset,
int expected, int x);
unsafe.cpp中C++方法(compareAndSwapInt实现):
//定义
UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env,
jobject unsafe, jobject obj, jlong offset, jint e, jint x))
UnsafeWrapper("Unsafe_CompareAndSwapInt");
//判断obj是否为空,返回obj指针的值
oop p = JNIHandles::resolve(obj);
//用p的地址加上offset得到具体内存地址
jint* addr = (jint *) index_oop_from_field_offset_long
(p, offset);
//通过Atomic::cmpxchg实现比较替换,其中参数x是即将更新的值,
参数e是原内存的值
return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
UNSAFE_END
//内联汇编
inline jint Atomic::cmpxchg (jint exchange_value,
volatile jint* dest, jint compare_value) {
int mp = os::isMP(); //判断是否是多处理器
//volatile表示禁止编译器优化
__asm__ volatile (
//根据当前系统是否为多核处理器决定是否为cmpxchg指令
添加lock前缀
LOCK_IF_MP(%4) "cmpxchgl %1,(%3)"
: "=a" (exchange_value)
: "r" (exchange_value), "a" (compare_value), "r" (dest),
"r" (mp)
: "cc", "memory");
}
总结:
CAS操作实现:
用预期值A1和内存值A2做对比,如果A1等于A2,则内存值修改成B并返回true,
否则不操作并返回false。
缺点:
ABA问题:多线程时,其余线程修改内存值之后又还原为初始值,
当前线程比较值时,值一样则操作成功。
解决办法:
java并发包中提供了一个带有标记的原子引用类AtomicStampedReference,
通过控制变量值的版本来保证CAS的正确性。
AtomicStampedReference以一个int值作为版本号,
每次更改前先取到这个int值的版本号,
等到修改的时候,比较当前版本号与当前线程持有的版本号是否一致,
如果一致,则进行修改,并将版本号+1。