如 指令),不会造成所谓的数据不一致问题,提供的CAS方法( 二 )


CAS 的全称为 -And-Swap ,它是一条 CPU 并发原语。
【如指令),不会造成所谓的数据不一致问题,提供的CAS方法】它的功能是判断内存某个位置的值是否为预期值,如果是则更改为新的值,这个过程是原子的 。
类主要利用 CAS ( and swap) +和方法来保证原子操作,从而避免的高开销,执行效率大为提升 。
CAS 并发原语体现在 JAVA 语言中就是 sun.misc. 类中的各个方法 。调用类中的 CAS 方法,JVM 会帮我们实现出 CAS 汇编指令 。这是一种完全依赖于 硬件的功能,通过它实现了原子操作 。再次强调,由于 CAS 是一种系统原语,原语属于操作系统用语范畴,是由若干条指令组成的,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许被中断,也就是说 CAS 是一条 CPU 的原子指令,不会造成所谓的数据不一致问题 。
3.3、源码分析new ().();
源码里面查看下 .java
假设线程 A 和线程 B 两个线程同时执行操作(分别跑在不同 CPU 上):
1里面的 value 原始值为 3 ,即主内存中的 value 为 3 ,根据 JMM 模型,线程 A 和线程 B 各自持有一份值为 3 的 value 的副本分别到各自的工作内存 。
2 线程 A 通过 (var1, var2) 拿到 value 值 3 ,这时线程 A 被挂起 。
3 线程 B 也通过 (var1, var2) 方法获取到 value 值 3 ,此时刚好线程 B 没有被挂起并执行方法比较内存值也为 3 ,成功修改内存值为 4 ,线程 B 打完收工,一切 OK。
4 这时线程 A 恢复,执行方法比较,发现自己手里的值数字 3 和主内存的值数字 4 不一致,说明该值已经被其它线程抢先一步修改过了,那 A 线程本次修改失败,只能重新读取重新来一遍了 。
5 线程 A 重新获取 value 值,因为变量 value 被修饰,所以其它线程对它的修改,线程 A 总是能够看到,线程 A 继续执行进行比较替换,直到成功 。
3.4、底层汇编 3.4.1、修饰的方法代表是底层方法
类中的,是一个本地方法,该方法的实现位于.cpp中
UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))UnsafeWrapper("Unsafe_CompareAndSwapInt"); oop p = JNIHandles::resolve(obj); // 先想办法拿到变量value在内存中的地址,根据偏移量valueOffset,计算 value 的地址 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
(::(x, addr, e)) == e;
3.4.2、
// 调用中的函数 来进行比较交换,其中参数x是即将更新的值,参数e是原内存的值
(jint) (::(x, addr, e)) == e;
unsigned Atomic:: cmpxchg (unsigned int exchange_value,volatile unsigned int* dest, unsigned int compare_value) {assert(sizeof(unsigned int) == sizeof(jint), "more work to do"); /* * 根据操作系统类型调用不同平台下的重载函数,这个在预编译期间编译器会决定调用哪个平台下的重载函数*/ return (unsigned int)Atomic::cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value); }
3.4.3、在不同的操作系统下会调用不同的重载函数,
inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value) {//判断是否是多核CPU int mp = os::is_MP(); __asm { //三个move指令表示的是将后面的值移动到前面的寄存器上 mov edx, dest mov ecx, exchange_value mov eax, compare_value //CPU原语级别,CPU触发 LOCK_IF_MP(mp) //比较并交换指令 //cmpxchg: 即“比较并交换”指令 //dword: 全称是 double word 表示两个字,一共四个字节 //ptr: 全称是 pointer,与前面的 dword 连起来使用,表明访问的内存单元是一个双字单元//将 eax 寄存器中的值(compare_value)与 [edx] 双字内存单元中的值进行对比,//如果相同,则将 ecx 寄存器中的值(exchange_value)存入 [edx] 内存单元中 cmpxchg dword ptr [edx], ecx } }