我可以假设用户线程和Java中的终结线程之间没有“无数据竞争”

时间:2013-12-12 13:19:55

标签: java multithreading race-condition finalize

考虑以下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节)的开头有一个发生前的边缘。

编辑:我认为有必要使我的问题更加准确,所以这里是尝试精确地重新解决问题:

如果我保证永远不会调用X.foo()(直接或间接),Java是否保证特定方法X.finalize()X.foo()之间的发生在之前的关系从任何finalize()方法?在这里,发生之前的解释完全按照§17.4.5中的定义进行解释。

3 个答案:

答案 0 :(得分:1)

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

所以我认为你不应该担心。

“但之前没有说过发生过关系的事情 在finalize()和一般方法之间“

那是因为那些方法(一般而言)不受管理/调用 由JVM但由你。所以它什么都不能说
顺便说一句,如果应用程序代码仍然可以调用foo(),这意味着这个应用程序
代码引用了您的对象,因此您的对象不符合条件 用于垃圾收集(即用于调用finalize()) 所以,你知道,我怀疑你的担忧是否有根据

<强>更新

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

假设相反 - &gt;想象一下你得到的情况。

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

答案 1 :(得分:1)

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

访问变量,则同样有效

- &GT; When does java thread cache refresh happens?

答案 2 :(得分:0)

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

我认为java内存模型基本上说每个线程都是自己运行的,并且看到其他线程的动作是未定义的,因此也是平台相关的顺序。只有通过使用Happens Before中描述的操作,您才能实现已定义的订单。

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

由于这样的bug很难找到,我开发了一个名为vmlens的工具,它使用一种名为eraser的算法检测竞争条件