我可以假设用户线程和 Java 中的最终线程之间'no data race'吗



考虑以下Java类:

class X {
    public void foo() {
        bar = 1;
    }
    protected void finalize() {
        if (bar == 1)
            baz();
    }
    private int bar = 0;
}

假设X.foo()从未从任何finalize()方法(直接或间接)调用过,我能确定上面的代码没有数据竞争吗?也就是说,我能确保X.finalize()在实际调用X.foo()的每种情况下都看到了X.foo()写的值吗?

天真的分析会说X.finalize()不能与X.foo()同时运行(由于上述假设),因此不需要额外的同步。

我猜上面的代码没有数据竞赛,但让我感到困扰的是,语言规范在§17.4.5中包含了以下明确的语句,但没有说明finalize()和方法之间的"先发生后发生"关系:

从一个对象的构造函数的末尾到该对象的终结器的开头(§12.6),存在一个发生在前的边。

编辑:我认为有必要使我的问题更加精确,因此这里尝试对问题进行精确的重新表述:

如果我保证从不从任何finalize()方法(直接或间接)调用X.foo(),Java是否保证在特定方法X.foo()X.finalize()之间的关系之前发生?这里,发生在被准确解释为§17.4.5中定义的之前。

由于每个线程都有一个变量缓存,因此它不是线程安全的,在其他工作中,每个线程都拥有自己的变量视图。可以将volatine应用于该变量,以强制线程加载该变量。如果从synchronized块访问变量,则同样有效

->java线程缓存何时刷新?

在Java中设置/获取int值无论如何都是原子AFAIK

所以我认为你不应该担心

"但没有提及之前发生的关系
finalize()和一般方法之间"

这是因为这些方法(通常)不是管理/调用的
由JVM决定,但由您决定。所以它什么也说不出来

顺便说一句,如果应用程序代码仍然可以调用foo(),这意味着这个应用程序
代码引用了您的对象,因此您的对象不符合条件
用于垃圾收集(即,用于要调用的finalize())
所以,你知道,我怀疑你的担心有任何理由

更新:

"Java是否保证特定方法X.foo()和
之间的关系在发生之前X.finalize()如果我保证X.foo()永远不会(直接或间接)从
任何finalize方法"
"调用

假设相反的情况->想象一下你遇到的情况。

finalize()方法是在对象x上调用的;然后有人在这个对象x(注意:x已经死了,即垃圾收集)对象上调用foo()。这听起来可能吗?对我来说不是。

否。在foo()和finalize()之间没有先发生后发生的关系。这基本上意味着您可能在字段栏的方法finalize()中看到零。

我认为java内存模型基本上说,每个线程都在自己的线程上运行,并以未定义的、因此依赖于平台的顺序查看其他线程的操作。只有通过使用"在实现定义的顺序之前发生"中描述的操作。

在您的情况下,finalize()方法可能看不到在不同线程中运行的foo方法中写入的值1。其中一个原因可能是,这两个线程在不同的cpu内核上运行,这些内核使用内存缓存。

由于像这样的错误很难找到,我开发了一个名为vmlens的工具,它使用一种名为橡皮擦的算法来检测竞争条件

最新更新