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

时间:2018-01-15 01:38:26

标签: java multithreading concurrency visibility safe-publication

我们说我们有一个班级

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();
}

是不可能抛出AssertionError,因为before-before是传递的?

尽管Foo' sx不是最终的,但由于Thread.start()的发生前保证,来自实例化Foo的线程的新创建的线程将看到所有更新,直到调用了Thread。开始()。

然而,这个线程也产生了许多子线程,并且由于之前有一个发生在之前的关系,我们可以说因为之前发生的传递属性,AssertionError永远不会抛出吗?

1 个答案:

答案 0 :(得分:4)

你的问题:

  

由于再次出现了先发生过的关系,我们可以这么说吗   因为之前发生的传递属性,那   永远不会抛出AssertionError?

答案是肯定的。正如我们在JLS8 section 17.4.5. Happens-before Order中看到的那样:

  
      
  • 如果是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(),first-action-in-second-assertion-thread)

(因为“对于每个线程t,t中的同步动作(第17.4.2节)的同步顺序与t。的程序顺序(第17.4.3节)一致”,我可以省略以下步骤:之间,如while(true)循环)