JVM 6里面可以看到很多的CAS的操作,而我们来看看JVM里面是怎么实现CAS的操作,至于原子操作的语义在这里我们就不介绍了
核心java源码是unsafe.java
compareAndSwapObject
compareAndSwapInt
compareAndSwapLong
。。。。
具体我们主要来看看 如何实现compareAndSwapObject的方法
unsafe.cpp
UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject e_h, jobject x_h)) UnsafeWrapper("Unsafe_CompareAndSwapObject"); oop x = JNIHandles::resolve(x_h); oop e = JNIHandles::resolve(e_h); oop p = JNIHandles::resolve(obj); HeapWord* addr = (HeapWord *)index_oop_from_field_offset_long(p, offset); if (UseCompressedOops) { update_barrier_set_pre((narrowOop*)addr, e); } else { update_barrier_set_pre((oop*)addr, e); } oop res = oopDesc::atomic_compare_exchange_oop(x, addr, e); jboolean success = (res == e); if (success) update_barrier_set((void*)addr, x); return success; UNSAFE_END
首先通过offset找到object 里的所要修改的field 的地址,接着就是在这个地址上内容交换,这里的要改变的内容实际上就是object的地址。
oopDesc::atomic_compare_exchange_oop
其中对压缩的object的地址重新计算,在opp.inline.hpp的文件中
inline narrowOop oopDesc::encode_heap_oop_not_null(oop v) { assert(!is_null(v), "oop value can never be zero"); assert(check_obj_alignment(v), "Address not aligned"); assert(Universe::heap()->is_in_reserved(v), "Address not in heap"); address base = Universe::narrow_oop_base(); int shift = Universe::narrow_oop_shift(); uint64_t pd = (uint64_t)(pointer_delta((void*)v, (void*)base, 1)); assert(OopEncodingHeapMax > pd, "change encoding max if new encoding"); uint64_t result = pd >> shift; assert((result & CONST64(0xffffffff00000000)) == 0, "narrow oop overflow"); assert(decode_heap_oop(result) == v, "reversibility"); return (narrowOop)result; }
让我们看看最后在x86里面linux下所调用的原子指令,在c++里面使用内联汇编,定义在atomic_linux_x86.include.hpp里
inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value) { bool mp = os::is_MP(); __asm__ __volatile__ (LOCK_IF_MP(%4) "cmpxchgq %1,(%3)" : "=a" (exchange_value) : "r" (exchange_value), "a" (compare_value), "r" (dest), "r" (mp) : "cc", "memory"); return exchange_value; }