考虑以下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中的定义进行解释。
答案 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
块
答案 2 :(得分:0)
没有。在foo()和finalize()之间的关系之前没有发生过。这基本上意味着您可能在字段栏的方法finalize()中看到零。
我认为java内存模型基本上说每个线程都是自己运行的,并且看到其他线程的动作是未定义的,因此也是平台相关的顺序。只有通过使用Happens Before中描述的操作,您才能实现已定义的订单。
在你的情况下,finalize()方法可能看不到在另一个线程中运行的foo方法中写入的值1。其中一个原因可能是,两个线程在不同的cpu内核上运行,后者使用内存缓存。