AtomicLong.lazySet 是如何工作的?

原文:http://www.quora.com/Java-programming-language/How-does-AtomicLong-lazySet-work

Jackson Davis说:为一个 AtomicLong 对象设置一个值,JVM 会确保其他线程读取到最新值,原子类和 voliatile 变量也是一样的,这是由依赖于硬件的系统指令(如 x86 的 xchg )实现的。lazySet 却是无法保证这一点的方法,所以其他线程在之后的一小段时间里还是可以读到旧的值。

这有什么好处呢?

性能:在多核处理器下,内存以及 CPU 缓存的读和写常常是顺序执行的,所以在多个 CPU 缓存之间同步一个内存值的代价是很昂贵的。

如何实现呢?

大多数的原子类,比如 AtomicLong 本质上都是一个 Unsafe 和一个 volatile Long 变量的包装类。值得注意的是 AtomicLong.lazySet 方法实际是调用了本地方法 Unsafe.putOrderedLong,本地方法 Unsafe.putOrderedLong 的实现可以参考 http://hg.openjdk.java.net/jdk7/…。

public final void lazySet(int newValue) {
unsafe.putOrderedInt(this, valueOffset, newValue);
}

从 Unsafe 的代码中可以发现 Unsafe_setOrderedLong 是一个本地方法(c++ 实现),它仅调用了 SET_FIELD_VOLATILE,这很是奇怪,我们期望共享的 Unsafe_setLongVolatile 拥有不同的语义。

PS:在非增强版本中,setOrdered 仅仅是调用了 setVolatile 方法,很是让人失望。深入查看你会发现其实它们是相同的,SET_FIELD_VOLATILE 是一个 OrderAccess:release_store_fence 的包装。可以在 Linux x86的代码 http://hg.openjdk.java.net/jdk7/… 中找到此方法的实现,在 64bit x86 系统中采用 xchgq 来代码,64位版本指令的问题我上面有提到过。

ps:从理论上讲 lazySet 能比一个标准的 volatile 变量的写性能更好。但是我在 openJdk 里没有找到相关代码。

Felix Sulima说:

sun.misc.unsafe 很多方法被 JVM 增强了,JIT(just in time 运行时编译执行的技术)直接解释而忽略原始的实现。可以在这里找到这个例子:src/share/vm/classfile/vmSymbols.hpp@3facbb14e873列表中的 native 方法仅仅是非 JIT 环境下的一个备份的内部方法。例如,如果它没有被调用(我也不知道是什么原因),因此这些方法缺乏一些必要的优化。从 Talk from JAX London 的幻灯片 11-12 可以看到 AtomicLong.lazySet(…) 在 x86 系统上会被编译成 "mov" 指令。这里是 Google Group 里关于如何获得 JIT 装配的一个描述。

看的一脸懵逼。

猜你喜欢

转载自www.cnblogs.com/tuhooo/p/10579486.html