目录
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 操作,如果不支持则会通过加锁处理。