zoukankan      html  css  js  c++  java
  • openjdk源码分析之AtomicLong

    关键代码:

        private static final Unsafe unsafe = Unsafe.getUnsafe();
        private static final long valueOffset; // 底层value变量的偏移地址
        private volatile long value; //底层变量
    
    
    static {
            try {
                valueOffset = unsafe.objectFieldOffset
                    (AtomicLong.class.getDeclaredField("value"));
            } catch (Exception ex) { throw new Error(ex); }
        }
    
        public final boolean compareAndSet(long expect, long update) {
            return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
        }
    
    

    然后看unsafe.cpp中compareAndSwapLong的定义:

    JNINativeMethod

    {CC "compareAndSetLong", CC "(" OBJ "J""J""J"")Z", FN_PTR(Unsafe_CompareAndSetLong)}

    UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSetLong(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jlong e, jlong x)) {
      oop p = JNIHandles::resolve(obj);
      if (p == NULL) {
        volatile jlong* addr = (volatile jlong*)index_oop_from_field_offset_long(p, offset);
        return RawAccess<>::atomic_cmpxchg(x, addr, e) == e;
      } else {
        assert_field_offset_sane(p, offset);
        return HeapAccess<>::atomic_cmpxchg_at(x, p, (ptrdiff_t)offset, e) == e;
      }
    } UNSAFE_END
    
    template <DecoratorSet decorators>
    template <DecoratorSet ds, typename T>
    inline typename EnableIf<
      HasDecorator<ds, MO_SEQ_CST>::value, T>::type
    RawAccessBarrier<decorators>::atomic_cmpxchg_internal(T new_value, void* addr, T compare_value) {
      return Atomic::cmpxchg(new_value,
                             reinterpret_cast<volatile T*>(addr),
                             compare_value,
                             memory_order_conservative);
    }
    
    template<typename T, typename D, typename U>
    inline D Atomic::cmpxchg(T exchange_value,
                             D volatile* dest,
                             U compare_value,
                             atomic_memory_order order) {
      return CmpxchgImpl<T, D, U>()(exchange_value, dest, compare_value, order);
    }
    
    // Handle cmpxchg for integral and enum types.
    //
    // All the involved types must be identical.
    template<typename T>
    struct Atomic::CmpxchgImpl<
      T, T, T,
      typename EnableIf<IsIntegral<T>::value || IsRegisteredEnum<T>::value>::type>
    {
      T operator()(T exchange_value, T volatile* dest, T compare_value,
                   atomic_memory_order order) const {
        // Forward to the platform handler for the size of T.
        return PlatformCmpxchg<sizeof(T)>()(exchange_value,
                                            dest,
                                            compare_value,
                                            order);
      }
    };
    

    然后转到具体平台相关的实现类,比如mac下的src/hotspot/os_cpu/bsd_x86/atomic_bsd_x86.hpp

    template<>
    template<typename T>
    inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value,
                                                    T volatile* dest,
                                                    T compare_value,
                                                    atomic_memory_order /* order */) const {
      STATIC_ASSERT(8 == sizeof(T));
      __asm__ __volatile__ (  "lock cmpxchgq %1,(%3)"
                            : "=a" (exchange_value)
                            : "r" (exchange_value), "a" (compare_value), "r" (dest)
                            : "cc", "memory");
      return exchange_value;
    }
    

    可见mac下采用的是cmpxchgq汇编指令实现:

    __asm__ 内联汇编

    lock 锁消息总线保证互斥地使用这个内存地址

    AT&T汇编格式: 指令 源操作数 目的操作数

    cmpxchg : 用RAX中的值与目的操作数的值进行比较,如果相等,则设置ZF标志并把源操作数加载到目的操作数中,否则清除ZF标志并把目的操作数加载到RAX中。

    分析:lock cmpxchgq %1,(%3) 其中%1指exchange_value,%3指dest
    首先把compare_value加载到RAX,然后比较RAX与目的操作数(%3即dest)的值,如果相等则把%1即exchange_value的值设置到dest,返回RAX中的值即compare_value。否则把%3即dest中的值加载的RAX寄存器,然后返回RAX中的值。即如果相等返回的是compare_value,否则返回的是dest原来的值。最后那返回的值与比较的值进行比较,相等则返回true表示设置成功。
    return HeapAccess<>::atomic_cmpxchg_at(x, p, (ptrdiff_t)offset, e) == e;

  • 相关阅读:
    SVN服务器搭建和使用(一)
    log4j.properties配置详解
    List<Map>来导出Excel数据
    JavaFX 表格数据显示简单Demo
    Java数组
    oracle数据 在已有的重复的数据上加联合唯一约束
    MyEclipse 9极速优化
    Eclipse中自定义Library
    Python 爬虫 1 (转)
    装修步骤 1
  • 原文地址:https://www.cnblogs.com/andyhe/p/10919678.html
Copyright © 2011-2022 走看看