jvm Java -静态字段上的比较和交换

zhte4eai  于 2022-11-07  发布在  Java
关注(0)|答案(1)|浏览(114)

我想知道是否有任何方法可以在Java中使用Unsafe(更准确地说是compareAndSwapObject)对静态字段执行比较和交换操作。我尝试使用null和类对象(TheClass.class)作为第一个参数,但没有成功。
编辑:代码如下:

public class UnsafeTest
{

    public static long staticField = 0;

    public static void main(String[] args) throws Exception
    {
        Long l = 0L;
        Long res = 350L;
        Field f = Unsafe.class.getDeclaredField("theUnsafe");
        f.setAccessible(true);
        Unsafe unsafe = (Unsafe) f.get(null);
        long off = unsafe.staticFieldOffset(
                UnsafeTest.class.getDeclaredField("staticField"));
        unsafe.compareAndSwapObject(UnsafeTest.class, off, l, res);

        // null instead of UnsafeTest.class produces the same result
        Thread.sleep(1000L);
        System.out.println(staticField); // prints 0
    }

}

我想让它对字段staticField执行CAS,将其设置为350(任意值)。当在标准输出上打印其值时,它显示0;所以我想什么都没有改变,这两个都不是做我想做的事情的正确论据,假设这是可能的。
先谢谢你!

py49o6xq

py49o6xq1#

一个问题是,您在非引用类型的字段上使用compareAndSwapObject。由于该字段是long,因此您应该使用compareAndSwapLong
同样,compareAndSwapXXX方法返回一个boolean来表示交换是成功还是失败。你应该检查它......是否有任何其他线程可能在同一个字段上执行CAS操作。(如果没有可能,就不要麻烦CAS了。只要使用常规赋值即可。)
最后,我看了Java 8的源代码,我认为Unsafe.compareAndSwapXxx操作并不是设计来处理static字段的,它使用Class对象作为目标对象。相反,我认为您需要做如下操作:

Field f = Unsafe.class.getDeclaredField("theUnsafe");
    f.setAccessible(true);
    Unsafe unsafe = (Unsafe) f.get(null);
    long off = unsafe.staticFieldOffset(
            UnsafeTest.class.getDeclaredField("staticField"));
    Object target = unsafe.staticFieldBase(f);
    unsafe.compareAndSwapLong(target, off, 0L, 350L);

无论哪种方式,都不会检查off值对于执行CAS操作的对象的字段是否正确。因此,如果您出错,您可能会得到内存损坏(以及不正确的结果或JVM崩溃)...而不是一个干净的Java异常。这就是使用Unsafe所冒的风险!
上面已经说过了,任何使用Unsafe代码的代码都是不可移植的。而且您的代码在Java 9和更高版本中将失败,因为compareAndSwapXxx方法已经被删除。
在Java 9和更高版本中,正确的方法是使用VarHandle类;请参阅javadoc

相关问题