JUC中Atomic class之lazySet的一点疑惑

    xiaoxiao2024-05-24  122

    最近再次翻netty和disrupt的源码, 发现一些地方使用AtomicXXX.lazySet()/unsafe.putOrderedXXX系列, 以前一直没有注意lazySet这个方法, 仔细研究一下发现很有意思。我们拿AtomicReferenceFieldUpdater的set()和lazySet()作比较, 其他AtomicXXX类和这个类似。

    1 public void set(T obj, V newValue) { 2     // ... 3     unsafe.putObjectVolatile(obj, offset, newValue); 4} 5  6 public void lazySet(T obj, V newValue) { 7     // ... 8     unsafe.putOrderedObject(obj, offset, newValue); 9}

    1.首先set()是对volatile变量的一个写操作, 我们知道volatile的write为了保证对其他线程的可见性会追加以下两个Fence(内存屏障) 1)StoreStore // 在intel cpu中, 不存在[写写]重排序, 这个可以直接省略了 2)StoreLoad // 这个是所有内存屏障里最耗性能的 注: 内存屏障相关参考Doug Lea大大的cookbook (http://g.oswego.edu/dl/jmm/cookbook.html)

    2.Doug Lea大大又说了, lazySet()省去了StoreLoad屏障, 只留下StoreStore 在这里 http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6275329 把最耗性能的StoreLoad拿掉, 性能必然会提高不少(虽然不能禁止写读的重排序了保证不了可见性, 但给其他应用场景提供了更好的选择, 比如上边连接中Doug Lea举例的场景)。

    但是但是, 在好奇心驱使下我翻了下JDK的源码(unsafe.cpp):

    01// 这是unsafe.putObjectVolatile() 02 UNSAFE_ENTRY(void, Unsafe_SetObjectVolatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject x_h)) 03     UnsafeWrapper("Unsafe_SetObjectVolatile"); 04     oop x = JNIHandles::resolve(x_h); 05     oop p = JNIHandles::resolve(obj); 06     void* addr = index_oop_from_field_offset_long(p, offset); 07     OrderAccess::release(); 08     if (UseCompressedOops) { 09         oop_store((narrowOop*)addr, x); 10     } else { 11         oop_store((oop*)addr, x); 12     } 13     OrderAccess::fence(); 14UNSAFE_END 15  16// 这是unsafe.putOrderedObject() 17 UNSAFE_ENTRY(void, Unsafe_SetOrderedObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject x_h)) 18     UnsafeWrapper("Unsafe_SetOrderedObject"); 19     oop x = JNIHandles::resolve(x_h); 20     oop p = JNIHandles::resolve(obj); 21     void* addr = index_oop_from_field_offset_long(p, offset); 22     OrderAccess::release(); 23     if (UseCompressedOops) { 24         oop_store((narrowOop*)addr, x); 25     } else { 26         oop_store((oop*)addr, x); 27     } 28     OrderAccess::fence(); 29UNSAFE_END

    仔细看代码是不是有种被骗的感觉, 他喵的一毛一样啊. 难道是JIT做了手脚?生成汇编看看

    生成assembly code需要hsdis插件

    mac平台从这里下载 https://kenai.com/projects/base-hsdis/downloads/directory/gnu-versions

    linux和windows可以从R大的[高级语言虚拟机圈子]下载 http://hllvm.group.iteye.com/

    为了测试代码简单, 使用AtomicLong来测:

    01// set() 02 public class LazySetTest { 03     private static final AtomicLong a = new AtomicLong(); 04  05     public static void main(String[] args) { 06         for (int i = 0; i < 100000000; i++) { 07             a.set(i); 08         } 09     } 10} 11  12// lazySet() 13 public class LazySetTest { 14     private static final AtomicLong a = new AtomicLong(); 15  16     public static void main(String[] args) { 17         for (int i = 0; i < 100000000; i++) { 18             a.lazySet(i); 19         } 20     } 21}

    分别执行以下命令:

    01 1.export LD_LIBRARY_PATH=~/hsdis插件路径/ 02 2.javac LazySetTest.java && java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly LazySetTest 03  04// ------------------------------------------------------ 05// set()的assembly code片段: 06 0x000000010ccbfeb3: mov    %r10,0x10(%r9) 07 0x000000010ccbfeb7: lock addl $0x0,(%rsp)     ;*putfield value 08                                             ; - java.util.concurrent.atomic.AtomicLong::set@2 (line 112) 09                                             ; - LazySetTest::main@13 (line 13) 10 0x000000010ccbfebc: inc   
    转载请注明原文地址: https://yun.8miu.com/read-128530.html
    最新回复(0)