并发编程 — 原子类 AtomicLong 详解

目录

1、AtomicLong的基本用法

2、AtomicLong内幕

2.1、JVM 源码分析

2.2、 AtomicLong 的部分源码

3、总结


1、AtomicLong的基本用法

与AtomicInteger非常类似,AtomicLong提供了原子性操作long类型数据的解决方案,AtomicLong所提供的原子性方法在使用习惯上也与AtomicInteger非常一致。我们不再详细解释每一个方法如何使用,可以参考 《AtomicInteger》 。AtomicInteger类中最为关键的方法为compareAndSwapInt,同样,在AtomicLong类中也提供了类似的方法compareAndSwapLong,但是该方法要比compareAndSwapInt复杂很多。

2、AtomicLong内幕

2.1、JVM 源码分析

我们知道 long 类型 占用 8 字节 64位,在某些机器硬件可能不支持 8 字节 64 位的 cmpxchg CPU 指令,那么此时就需要判断当前JVM版本是否支持8字节数字的cmpxchg操作;如果机器硬件与当前JVM的版本都不支持,那么实际上针对long型数据的原子性操作将不会是Lock Free的,而是需要采用加锁的方式确保原子性。我们看下 hotspot JVM中针对 AtomicLong的源码,具体路径:src\share\vm\prims\unsafe.cpp

// CompareAndSwapLong 方法

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapLong(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jlong e, jlong x))
  UnsafeWrapper("Unsafe_CompareAndSwapLong");
  Handle p (THREAD, JNIHandles::resolve(obj));
  jlong* addr = (jlong*)(index_oop_from_field_offset_long(p(), offset));
#ifdef SUPPORTS_NATIVE_CX8 //判断是 CPU 否支持 8 字节操作
  return (jlong)(Atomic::cmpxchg(x, addr, e)) == e;
#else
  if (VM_Version::supports_cx8()) //判断 JVM 是否支持 8 字节操作
    return (jlong)(Atomic::cmpxchg(x, addr, e)) == e;
  else {
    jboolean success = false;
    // 不支持 将进行 加锁操作
    MutexLockerEx mu(UnsafeJlong_lock, Mutex::_no_safepoint_check_flag);
    jlong val = Atomic::load(addr);
    if (val == e) { Atomic::store(x, addr); success = true; }
    return success;
  }
#endif
UNSAFE_END

2.2、 AtomicLong 的部分源码

我们再回过头来看看 AtomicLong 的部分源码,不难发现 VM_SUPPORTS_LONG_CAS 在AtomicLong中的定义,其作用与 SUPPORTS_NATIVE_CX8 及 VM_Version::supports_cx8()是一致的。



    /**
     * Records whether the underlying JVM supports lockless
     * compareAndSwap for longs. While the Unsafe.compareAndSwapLong
     * method works in either case, some constructions should be
     * handled at Java level to avoid locking user-visible locks.
     */
    static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();

    /**
     * Returns whether underlying JVM supports lockless CompareAndSet
     * for longs. Called only once and cached in VM_SUPPORTS_LONG_CAS.
     */
    private static native boolean VMSupportsCS8();

3、总结

AtomicLong 的使用跟 AtomicInteger 使用方式是一样的,但是有一点需要注意的是,在编译器编译成字节码时,会先判断 当前JVM 或者 机器硬件是否支持 8字节的CAS操作,如果支持则通过 Free Lock 操作,如果不支持则会通过加锁处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值