java Unsafe库如何帮助原子变量实现线程安全?

gab6jxml  于 2023-01-24  发布在  Java
关注(0)|答案(2)|浏览(112)

我一直在阅读关于Compare and Swap(CAS)如何在幕后工作的网络文章,因为AtomicInteger、AtomicLong和其他原子变量都使用JNI的“Unsafe”库的compareAndSet()方法,但当你进入实际实现时,你会得到一个空白的、抽象的方法,它没有告诉你compareAndSet()实际上是如何线程安全的。

@HotSpotIntrinsicCandidate
public final native boolean compareAndSetLong(Object o, long offset,
                                              long expected,
                                              long x);

有人想知道JNI的Unsafe库如何保证原子变量的线程安全性吗?

fae0ux8s

fae0ux8s1#

注意JNI和Unsafe是不相关的:Unsafe不是JNI的一部分,正如已经指出的,尽管有本机方法,但Unsafe不是用JNI实现的。
它在VM中直接链接到一些通用的Atomic::cmpxchg,然后您必须根据您的平台(这里是linux-amd 64)通过一些模板层跟踪到适当的实现。

ovfsdjhp

ovfsdjhp2#

实现起来相当简单,分为两个部分:一个JNI方法,它使指令作为字节码解释计算的一部分可用;一个内在函数,它使指令在JIT编译器生成本机代码时可用。

JNI方法

cpp将实现显示为JNI方法:

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSetLong(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jlong e, jlong x)) {
  oop p = JNIHandles::resolve(obj);
  volatile jlong* addr = (volatile jlong*)index_oop_from_field_offset_long(p, offset);
  return Atomic::cmpxchg(addr, e, x) == e;
} UNSAFE_END

Atomic::cmpxchg分派到执行CAS的各种策略,您可以在OS+CPU specific file

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

也有1字节和8字节CAS的实现,但唯一的区别分别是cmpxchgbcmpxchgq

JVM固有

正如你的问题的注解中所提到的,这个方法也被标记为@HotspotIntrinsicCandidate.(在最近的JVM中是@IntrinsicCandidate)。JVM通过类和方法名来保存list of all intrinsic candidates。类文件解析器将方法与声明的内部函数相关联。从那里,JIT编译器可以检测到对具有内部函数的方法的调用,并将其替换为内联版本或仅针对该指令的汇编片段。

相关问题