gpt4 book ai didi

Java 重新排序和不稳定问题

转载 作者:行者123 更新时间:2023-11-29 05:13:09 28 4
gpt4 key购买 nike

我最近遇到了一个有趣的问题:

例如我有 A 类:

class A {
int a;
int b;

public A() {
a = 1;
b = 2;
}

public int getA() {return a;}
public int getB() {return b;}
}

A 类必须仅作为单例存在;因此,为了提供对单例的访问,我创建了类工厂:

class Factory {
private A a;
public A getA() {
if (a == null) {
synchronized(this) {
if (a == null) {
a = new A();
}
}
}
return a;
}

据我了解,根据 JVM 中的重新排序,如果 2 个线程同时访问 Factory.getA() ,则其中一个线程可能会获得部分构造的对象,这可能会导致应用程序崩溃。

但如果我将 A 设为私有(private); volatile 我可以确定每个线程只会访问完全构造的对象吗?

因此,作为结论,如果我将变量 x 标记为易变的,它会影响 x.class 构造函数的内容吗?

最佳答案

But in case if i make private A a; volatile can i be sure that each thread will access only completely constructed object?

是的。

考虑线程 #1 初始化 a 的情况。工厂互斥锁确保一次只有一个线程可以创建 A。所以我们有以下顺序:

  1. 线程 #1 发现 a 为空

  2. 线程 #1 获取互斥量。

  3. 线程 #1 看到 a 仍然是 null。

  4. 线程 #1 构造了一个 A 实例,它初始化了它的变量。

  5. 线程 #1 将实例引用分配给 a

  6. 线程 #1 释放锁。

对于线程 #2 在非空状态下看到 a(例如,在步骤 #1 或步骤 #3 测试中),这意味着线程 #1 必须已经到达 (至少)步骤#5。但这意味着

A.a = 1;                    // thread #1

“发生在”

A.b = 2;                    // thread #1

“发生在”

write to Factory.a          // thread #1

“发生在”

read from Factory.a         // thread #2

“发生在”

access to some field of `A` // thread #2

因为从线程 #1 中新 A 的字段初始化到线程 #2 中的字段访问,存在完整的“先于发生”关系链。这意味着线程 #2 保证看到字段初始化写入的结果......除非有其他干预写入这些字段。

请注意,写入 volatile a 和随后在另一个线程中读取之间的“发生在之前”是关键。如果 a 不是易变的,那么就没有完整的“先发生”链,因此执行不是“先发生一致”;即它包含一个“数据竞争”。

我在上面使用/遵循的术语和推理来自 Java 语言规范,Chapter 17.4 .

关于Java 重新排序和不稳定问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27565600/

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