gpt4 book ai didi

java - Java内存模型中局部最终变量的语义?

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:58:59 24 4
gpt4 key购买 nike

以下代码有时会在我的 Windows PC 和 Mac 上打印“valueWrapper.isZero()”,都在服务器模式下运行他们的 JVM。好的,这是因为值字段在 ValueWrapper 类中不是最终的,所以有可能某个线程看到了陈旧的值 0。

public class ConcurrencyApp {
private final Random rand = new Random(System.currentTimeMillis());
private ValueWrapper valueWrapper;

private static class ValueWrapper {
private int value;

public ValueWrapper(int value) {
this.value = value;
}

public boolean isZero() {
return value == 0;
}
}

private void go() {
while (true) {
valueWrapper = new ValueWrapper(randomInt(10, 1024));
Thread thread = new Thread(new Runnable() {

@Override
public void run() {
if (valueWrapper.isZero()) {
System.out.println("valueWrapper.isZero()");
}
}
});
thread.start();
}
}

private int randomInt(int min, int max) {
int randomNum = rand.nextInt((max - min) + 1) + min;
return randomNum;
}

public static void printVMInfos() {
String vmName = System.getProperty("java.vm.name");
System.out.println("vm name: " + vmName);
int cores = Runtime.getRuntime().availableProcessors();
System.out.println("available cores: " + cores);
}

public static void main(String[] args) {
ConcurrencyApp app = new ConcurrencyApp();
printVMInfos();
app.go();
}
}

但是下面的修改呢,这里我使用了一个局部最终变量:

private void go() {
while (true) {
final ValueWrapper valueWrapper = new ValueWrapper(randomInt(10, 1024));
Thread thread = new Thread(new Runnable() {

@Override
public void run() {
if (valueWrapper.isZero()) {
System.out.println("valueWrapper.isZero()");
}
}
});

thread.start();
}
}

看起来现在没有线程看到过时值 0。但这由 JMM 保证吗?简要看一下规范并不能说服我。

最佳答案

It looks like that now no thread sees a stale value of 0. But is this guaranteed by the JMM? A brief look in the spec doesn't convinced me.

这是有保证的,但不是因为 final。当你 fork 一个线程时,有一个 happens-before 保证。 在您启动新线程之前在 fork 线程中完成的任何内存操作都保证被新线程视为完全构造和发布。引用自JLS 17.4.4 - Synchronization Order :

An action that starts a thread synchronizes-with the first action in the thread it starts.

当我们谈论对象构造和发布时,这与 final 字段不同。如果一个字段final,那么当构造函数完成并且对象被发布到多个线程时,它保证被正确初始化。在您的情况下, final 是必需的,因为匿名类。如果您没有使用匿名类,那么您可以删除 ValueWrapper 上的 final,由于上述原因,您的对象仍然可以保证完全构建。

仅供引用,请在此处查看final 字段信息:Java concurrency: is final field (initialized in constructor) thread-safe?

关于java - Java内存模型中局部最终变量的语义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21439275/

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