Java final字段是否保证字段值在不同线程中可见?

Java final字段是否保证字段值在不同线程中可见?,java,multithreading,concurrency,jcstress,Java,Multithreading,Concurrency,Jcstress,我正在使用JCStress测试最终变量。我知道final可以用来确保在构造对象时,访问该对象的另一个线程不会看到处于部分构造状态的对象。 现在我有一个类a.java public class A { final int f; A() { this.f = 42; } } 据我所知,构造函数应该这样执行 A temp = <new> temp.f = 42 <freeze value> fv = temp 现在,为什么我在输出

我正在使用
JCStress
测试最终变量。我知道
final
可以用来确保在构造对象时,访问该对象的另一个线程不会看到处于部分构造状态的对象。 现在我有一个类a.java

public class A {
    final int f;

    A() {
        this.f = 42;
    }

}
据我所知,构造函数应该这样执行

A temp = <new>
temp.f = 42
<freeze value>
fv = temp
现在,为什么我在输出中看到值0?我的CPU架构是x86,所以用负载重新排序存储也没有意义。我得到的输出是

           0    94,922,153     FORBIDDEN  No default case provided, assume FORBIDDEN                  
          42    48,638,587     ACCEPTABLE  Final value initialized    
另外,我发现的另一件不寻常的事情是,当我将字段
a
声明为
static
时。我的输出只有42,这是为什么

          42   299,477,390     ACCEPTABLE  Final value initialized      
为什么我在输出中看到值0

reader()
方法中的
a==null(因此
result.r1
保留
0
)时,就是这种情况

当我将字段a声明为静态时。我的输出只有42,这是为什么

          42   299,477,390     ACCEPTABLE  Final value initialized      
您用
@State
注释了
FinalField
,因此jcstrest为每次执行创建一个新的
FinalField
实例。
如果
a
FinalField
中的一个实例字段,则每次执行时它最初都是
null


如果
a
FinalField
中的一个静态字段,那么它将在所有执行中共享,并且仅在第一次执行时
null

另一个答案已经解释了为什么
0
静态
但即使修复了这些问题,也很难重现部分初始化。

因此,我建议您看看JCStress源代码:它包含示例,其中一个()已经完成了您想要的功能。

解释非常简单。
result.r1的默认值是什么?什么类型的r1是
r1
?它是一个
int
,而
int
的默认值是
zero
。因此,如果(ta!=null)
未发生,则表示
ta
null
,则代码将不起任何作用。“nothing”表示将
r1
保留为其默认值,即(您现在已经知道)
0
。因此,当
ta==null
(并且隐式地
a==null
)时,您将
r1
保留为
0
,尽管您没有明确这样做

解决方案很简单:

@Actor
public void reader(I_Result result) {
    A ta = a;
    if (ta != null) {
        result.r1 = ta.f;
    } else {
        result.r1 = -1;
    }
}
以及:


现在,您的代码将永远不会显示
0
,如果将
a
读为非空,您将始终将
a.f
读为
42
。就您的理解而言,是的,所有线程一旦看到对
a
实例的引用,就会看到
42
——这是
JLS
保证。

那么,有没有办法测试变量f是否为0(即部分初始化),我从类a中删除了final。我只得到42。
@JCStressTest
@State
@Outcome(id = "42", expect = Expect.ACCEPTABLE, desc = "42 is OK")
@Outcome(id = "-1", expect = Expect.ACCEPTABLE, desc = "-1 is OK too")