调用 Thread.start() 时是否在传递之前发生?



假设我们有一个类

class Foo {
int x;
Foo() {
x = 5;
}
}

和一些客户端代码

public static void main(String[] args) {
Foo foo = new Foo();
new Thread(() -> {
while (true) {
new Thread(() -> {
if (foo.x != 5) {
throw new AssertionError("this statement is false 1");
}
new Thread(() -> {
if (foo.x != 5) {
throw new AssertionError("this statement is false 2");
}
}).start();
}).start();
}
}).start();
}

断言错误不可能被抛出,因为发生之前是可传递的吗?

尽管 Foo 的 x 不是最终的,但由于 Thread.start() 的先行保证,一个从实例化 Foo 的线程新创建的线程,将看到调用 Thread.Start() 之前的所有更新。

但是,这个线程也生成了许多子线程,并且由于再次存在发生之前的关系,我们是否可以说由于发生之前发生的传递属性,断言错误永远不会被抛出?

你的问题:

既然又有先发生过的关系,我们能不能说 由于发生之前发生的传递属性, 断言错误永远不会被抛出?

答案是肯定的。正如我们在 JLS8 第 17.4.5 节中看到的。发生前订单:

  • 如果 hb(x, y) 和 hb(y, z),则 hb(x, z)。

在JLS的同一部分中也给出了:

  • 对线程start()的调用发生在已启动线程中的任何操作之前。

所以有

  • hb(new Foo(), 第一线程中的第一操作)
  • HB(first-action-in-first-thread, first-action-in-first-assertion-thread)
  • HB(first-action-in-first-thread, first-action-in-second-assertion-thread)

这意味着还有:

  • hb(new Foo(), first-action-in-first-assertion-thread)
  • hb(new Foo(), 第一操作在第二断言线程)

(由于"对于每个线程 t,t 中同步操作 (§17.4.2) 的同步顺序与 t 的程序顺序 (§17.4.3) 一致",我可以省略中间的步骤,例如while(true)循环)

最新更新