首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >最终字段是否保证字段值在不同线程中可见?

最终字段是否保证字段值在不同线程中可见?
EN

Stack Overflow用户
提问于 2021-05-16 05:14:39
回答 3查看 97关注 0票数 3

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

代码语言:javascript
复制
public class A {
    final int f;

    A() {
        this.f = 42;
    }

}

据我所知,构造函数应按如下方式执行:

代码语言:javascript
复制
A temp = <new>
temp.f = 42
<freeze value>
fv = temp

现在我正在使用下面提到的测试。

代码语言:javascript
复制
@JCStressTest
@State
public class FinalField {
    A a;

    @Actor
    public void writer() {
        a = new A();
    }

    @Actor
    public void reader(I_Result result) {
        A ta = a;
        if (ta != null) {
            result.r1 = ta.f; 
        }
    }

}

现在,为什么我看到输出中的值为0?我的CPU架构是x86,所以用负载重新排序存储也是没有意义的。我得到的输出是

代码语言:javascript
复制
           0    94,922,153     FORBIDDEN  No default case provided, assume FORBIDDEN                  
          42    48,638,587     ACCEPTABLE  Final value initialized    

另外,我发现另一件不寻常的事情是,当我将字段a声明为static时。我的产出只有42,这是为什么?

代码语言:javascript
复制
          42   299,477,390     ACCEPTABLE  Final value initialized      
EN

回答 3

Stack Overflow用户

发布于 2021-05-16 11:43:54

为什么我看到输出中的值为0?

a == null (因此result.r1保持为0)在reader()方法中时,情况就是如此。

当我宣布字段a为静态的时候。我的产出只有42,这是为什么?

您用@State注释了@State,因此JCStress为每次执行创建了一个新的FinalField实例。

如果aFinalField中的实例字段,那么在每次执行中它最初都是null

如果aFinalField中的一个静态字段,那么它在所有执行过程中都是共享的,并且只有在第一次执行时才是null

票数 1
EN

Stack Overflow用户

发布于 2021-05-16 17:54:50

另一个答案已经解释了为什么您对0static有问题。

但是,即使解决了这些问题,也很难再现部分初始化。

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

票数 1
EN

Stack Overflow用户

发布于 2021-05-17 02:20:53

这个解释真的很简单。result.r1的默认值是什么?r1是什么类型的?它是一个intint的默认值是zero。因此,当这个if (ta != null)没有发生时,意味着tanull,您的代码将什么也不做。"nothing“转换为将r1保留为其默认值--即(您现在已经知道) zero。因此,当ta == null (以及隐式a == null)时,您将r1留给0,尽管您没有显式地这样做。

解决方案是微不足道的:

代码语言:javascript
复制
@Actor
public void reader(I_Result result) {
    A ta = a;
    if (ta != null) {
        result.r1 = ta.f;
    } else {
        result.r1 = -1;
    }
}

以及:

代码语言:javascript
复制
@JCStressTest
@State
@Outcome(id = "42", expect = Expect.ACCEPTABLE, desc = "42 is OK")
@Outcome(id = "-1", expect = Expect.ACCEPTABLE, desc = "-1 is OK too")

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67553393

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档