根据操作中的Java并发,如果我们有以下类:

public class Wrapper {
  private int num;

  public Wrapper(int num) {
    this.num = num;
  }

  public void assertCorrectness() {
    if (num != num)
      throw new AssertionError("This is false");
  }
}

我们初始化这个类的一个实例,并以非安全的方式(例如通过一个简单的公共字段)发布它,那么如果从另一个线程调用,assertCorrectness()可能确实会抛出一个AssertionError.换句话说,这意味着另一个线程可能会看到对实例的最新引用,但实例本身的状态可能已过期(因此线程可以看到对象存在,但它处于部分构造/不一致的状态).

另一方面,据说通过易失性引用发布此类的实例被认为是安全的.然而,我的理解是,Volatile只是保证任何线程都将始终看到引用的最新版本,而不是被引用的对象的状态.因此,我们可以确定,如果一个线程将包装器类的新实例分配给一个可变字段,那么所有其他线程都将看到该引用已更新.但是,他们是否仍然会看到处于不一致/部分构造状态的对象呢?

推荐答案

不,因为正在使用的volatile建立了一种事前关系.在没有它的情况下,允许各种重新排序和其他事情,这使得不一致的状态成为可能,但是有了它,JVM必须为您提供预期的结果.

在本例中,volatile用于可见性效果(线程看到最新的值),但之前happpens提供的安全发布.在解释volatile的用法时,经常忽略它的这一特性.

Java相关问答推荐

如何用javac编译Java类,即使对像java.lang.*这样的基本类也没有任何依赖关系?

更新我们的一个文物后出现了严重的符号引用错误

Java JAR环境(JRE)是否支持模块?

Java应用程序崩溃时试图读取联系人从电话

在现代操作系统/硬件上按块访问数据值得吗?

需要一个找不到的jakarta.sistence.EntityManager类型的Bean

名称冲突具有相同的擦除

如何创建一个2d自上而下的移动系统,其中移动,同时持有两个关键是可能的处理?

获取字符串中带空格的数字和Java中的字符

生成桥方法以解决具有相同擦除的冲突方法

GetChildren().emoveAll()不会删除 node

由于在生成器模式中使用泛型,lambda表达式中的返回类型错误

Dijkstra搜索算法的实现

IntelliJ IDEA中的JavaFX应用程序无法在资源中找到CSS文件

为了安全起见,有必要复制一份 list 吗?

将java.util.Date(01.01.0001)转换为java.time.LocalDate将返回29.12.0000

通过/失败的参数化junit测试方法执行数

Java 17与Java 8双重表示法

如何在Spring Boot中为不同的部署环境管理多个.properties文件?

多线程、并发和睡眠未按预期工作