gpt4 book ai didi

java - Java 中同步的可见性影响

转载 作者:行者123 更新时间:2023-11-29 07:25:56 24 4
gpt4 key购买 nike

This文章说:

In this noncompliant code example, the Helper class is made immutable by declaring its fields final. The JMM guarantees that immutable objects are fully constructed before they become visible to any other thread. The block synchronization in the getHelper() method guarantees that all threads that can see a non-null value of the helper field will also see the fully initialized Helper object.

public final class Helper {
private final int n;

public Helper(int n) {
this.n = n;
}

// Other fields and methods, all fields are final
}

final class Foo {
private Helper helper = null;

public Helper getHelper() {
if (helper == null) { // First read of helper
synchronized (this) {
if (helper == null) { // Second read of helper
helper = new Helper(42);
}
}
}

return helper; // Third read of helper
}
}

However, this code is not guaranteed to succeed on all Java Virtual Machine platforms because there is no happens-before relationship between the first read and third read of helper. Consequently, it is possible for the third read of helper to obtain a stale null value (perhaps because its value was cached or reordered by the compiler), causing the getHelper() method to return a null pointer.

我不知道该怎么办。我同意第一次和第三次阅读之间没有 happens before 关系,至少没有 immediate 关系。从某种意义上说,第一次读取必须发生在第二次之前,第二次读取必须发生在第三次之前,因此第一次读取必须发生在第三次之前,是否存在传递发生之前的关系

有人可以更熟练地详细说明吗?

最佳答案

不,没有传递关系。

JMM 背后的想法是定义 JVM 必须遵守的规则。只要 JVM 遵循这些规则,它们就有权根据需要重新排序和执行代码。

在您的示例中,第二次读取和第三次读取不相关 - 例如,使用 synchronizedvolatile 不会引入内存屏障。因此,允许 JVM 执行它如下:

 public Helper getHelper() {
final Helper toReturn = helper; // "3rd" read, reading null
if (helper == null) { // First read of helper
synchronized (this) {
if (helper == null) { // Second read of helper
helper = new Helper(42);
}
}
}

return toReturn; // Returning null
}

然后您的调用将返回空值。然而,会创建一个单例值。但是,后续调用可能仍会得到空值。

如建议的那样,使用 volatile 会引入新的内存屏障。另一种常见的解决方案是捕获读取的值并将其返回。

 public Helper getHelper() {
Helper singleton = helper;
if (singleton == null) {
synchronized (this) {
singleton = helper;
if (singleton == null) {
singleton = new Helper(42);
helper = singleton;
}
}
}

return singleton;
}

由于您依赖于局部变量,因此无需重新排序。一切都发生在同一个线程中。

关于java - Java 中同步的可见性影响,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52805020/

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