gpt4 book ai didi

java - 保证将成员变量值写入内存而不将其标记为 volatile

转载 作者:行者123 更新时间:2023-12-01 17:00:08 24 4
gpt4 key购买 nike

我有以下类(class):

public class Example {

private AtomicBoolean isValueSet = new AtomicBoolean(false);
private int value = 0; // I DON'T want to make this volatile.

private void initializeValue(int value) {
// as you can see, value can only ever be set once.
if (isValueSet.compareAndSet(false, true)) {
this.value = value;
}
}

public int getValue() {
return value;
}
}

Example类的值仅一次初始化,但必须Example 的实例之后初始化被 build 。这意味着我无法在构造函数中设置它(使其成为 final )。 Example.value是一个一次写入多次读取的成员变量。

问题:

我正在多线程环境中工作,因此该值可以在Thread 1上初始化是合理的。并继续阅读Thread 2 。这意味着在 Thread 1 设置值后,写入可能尚未从缓存刷新到内存,这意味着写入对 Thread 2 不可见。 .

在您继续阅读之前,我想明确指出,这个问题的关注点不是可能存在的任何竞争条件,而只是确保 initializeValue()调用确保将值写入内存。

虽然这是最简单的解决方案,但我在性能至关重要的多线程环境中工作,因此我不想想要制作 Example.value volatile .

问题:

现在我对“发生在之前”原则的理解意味着在 synchronized 内设置的任何值 block 会自动刷新到内存,因此我可以通过以下更改解决我的问题:

private void initializeValue(int value) {
// as you can see, value can only ever be set once.
if (isValueSet.compareAndSet(false, true)) {
synchronized (new Object()) {
this.value = value;
}
}
}

这是正确的吗?

<小时/>

编辑:

鉴于我们已经确定上述方法不起作用,请执行以下操作:

public class UnsafeUtil {

private static final Unsafe unsafe;

static {
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
unsafe = (sun.misc.Unsafe) field.get(null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

public static void setValue(Object instance, String fieldName, Object value) {
try {
Field field = instance.getClass().getDeclaredField(fieldName);
unsafe.putObjectVolatile(instance, unsafe.objectFieldOffset(field), value);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

}


public class Example {

private AtomicBoolean isValueSet = new AtomicBoolean(false);
private Object value = null;

private void initializeValue(Object value) {
// as you can see, value can only ever be set once.
if (isValueSet.compareAndSet(false, true)) {
UnsafeUtil.setValue(this, "value", value);
}
}

public Object getValue() {
return value;
}
}

最佳答案

不,这不正确。该值的读取器必须在同一对象上同步才能读取该值,然后应用发生之前原则。

来自the documentation :

An unlock (synchronized block or method exit) of a monitor happens-before every subsequent lock (synchronized block or method entry) of that same monitor. And because the happens-before relation is transitive, all actions of a thread prior to unlocking happen-before all actions subsequent to any thread locking that monitor.

关于java - 保证将成员变量值写入内存而不将其标记为 volatile ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28254798/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com