volatile和UNSAFE.putIntVolatile()之间的区别是什么

时间:2015-07-30 10:57:40

标签: java volatile

private static final long SEGSHIFT_OFFSET;
SEGSHIFT_OFFSET = UNSAFE.objectFieldOffset(
            ConcurrentHashMap.class.getDeclaredField("segmentShift"));
UNSAFE.putIntVolatile(this, SEGSHIFT_OFFSET, 32);

代码adove可以替换代码如下?

private static volatile long SEGSHIFT_OFFSET = 0L; 
SEGSHIFT_OFFSET = 32;

或可以更换如下?

private static synchronized long SEFSHIFT_OFFSET = 0L;
SEGSHIFT_OFFSET = 32;

1 个答案:

答案 0 :(得分:1)

我假设您在某个类中拥有此代码,该类是ConcurrentHashMap类的子类。

不,它无法按照您的建议进行更换。此代码非常危险:它使用新值更新segmentShift的包私有最终字段ConcurrentHashMapSEGSHIFT_OFFSET用于确定内存中segmentShift字段的偏移量(此字段位置与对象开头之间的字节数)。由于此偏移在JVM生命周期中被假定为常量,因此它存储在最终字段中。

您建议的替换完全不同:只需声明字段并更改其值即可。这样您就无法更改无法访问的最终segmentShift字段的值。它在更新后使用volatile语义更新内存屏障,因此其他线程将看到更新的值(尽管我仍然怀疑它是否是一种强大的方法)。

如果要替换此代码,可以尝试use reflection,尽管这不会强制使用在这种情况下可能需要的易失性语义。

请注意,这个不安全的代码在JDK8中无法完全发挥作用,因为ConcurrentHashMap的内部结构发生了显着变化,并且不再有segmentShift字段。如果你想升级到JDK8,那么反射也无济于事。

顺便提一下ongoing discussion关于完全删除Unsafe