gpt4 book ai didi

java - 我是否有重新排序问题,是否由于引用转义?

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:56:14 25 4
gpt4 key购买 nike

我有这个类,我在其中缓存实例并在使用它们时克隆它们(数据是可变的)。

我想知道我是否会遇到重新排序的问题。

我看过this answer和 JLS,但我仍然没有信心。

public class DataWrapper {
private static final ConcurrentMap<String, DataWrapper> map = new ConcurrentHashMap<>();
private Data data;
private String name;

public static DataWrapper getInstance(String name) {
DataWrapper instance = map.get(name);
if (instance == null) {
instance = new DataWrapper(name);
}
return instance.cloneInstance();
}

private DataWrapper(String name) {
this.name = name;
this.data = loadData(name); // A heavy method
map.put(name, this); // I know
}

private DataWrapper cloneInstance() {
return new DataWrapper(this);
}

private DataWrapper(DataWrapper that) {
this.name = that.name;
this.data = that.data.cloneInstance();
}
}

我的想法: 运行时可以重新排序构造函数中的语句并在初始化数据之前发布当前的DataWrapper实例(放在映射中) > 对象。第二个线程从 map 中读取 DataWrapper 实例并看到空的 data 字段(或部分构造)。

这可能吗?如果是,是否只是因为引用转义?

如果不是,您能否用更简单的术语解释一下如何推理发生在之前的一致性?

如果我这样做会怎样:

public class DataWrapper {
...
public static DataWrapper getInstance(String name) {
DataWrapper instance = map.get(name);
if (instance == null) {
instance = new DataWrapper(name);
map.put(name, instance);
}
return instance.cloneInstance();
}

private DataWrapper(String name) {
this.name = name;
this.data = loadData(name); // A heavy method
}
...
}

还会出现同样的问题吗?

请注意,如果多个线程尝试同时为相同的值创建和放置实例,我不介意创建一个或两个额外的实例。

编辑:

如果名称和数据字段是最终的或可变的怎么办?

public class DataWrapper {
private static final ConcurrentMap<String, DataWrapper> map = new ConcurrentHashMap<>();
private final Data data;
private final String name;
...
private DataWrapper(String name) {
this.name = name;
this.data = loadData(name); // A heavy method
map.put(name, this); // I know
}
...
}

还是不安全?据我了解,构造函数初始化安全保证仅适用于引用在初始化期间未转义的情况。我正在寻找证实这一点的官方消息来源。

最佳答案

如果你想符合规范,你不能应用这个构造函数:

private DataWrapper(String name) {
this.name = name;
this.data = loadData(name);
map.put(name, this);
}

正如您所指出的,JVM 可以将其重新排序为:

private DataWrapper(String name) {
map.put(name, this);
this.name = name;
this.data = loadData(name);
}

当为 final 字段赋值时,这意味着在构造函数的末尾 执行所谓的卡住操作。内存模型保证此卡住操作与应用此卡住操作的实例的任何取消引用之间存在先于发生的关系。然而,这种关系只存在于构造函数的末尾,因此,你打破了这种关系。通过将发布拖出您的构造函数,您可以修复此关系。

如果你想更正式地了解这段关系,我推荐looking through this slide set .我也解释了in this presentation starting at about minute 34的关系.

关于java - 我是否有重新排序问题,是否由于引用转义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46592723/

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