thread.start 之前发生的所有事情对调用 start 的线程可见吗?

Is everything that happened before thread.start visible to the thread that is spawned calling start?

现在在 Whosebug 上已经有了很好的答案,但他们没有给我想要的明确答案。

假设你有一个方法

Dosomething();
 doAnother();
  int x = 5;
  Runnable r = new Runnable(){
     public void run(){
     int y = x;
     x = 7;
     System.out.println(z);}
   }
   new Thread(r).start()

现在这个方法是 运行 并且在调用 thread.start 之前,一些全局非易失性变量 z 从 4 更改为 5。

程序能保证打印 5 因为 z 发生在 thread.start 之前吗?

此外,如果我们以某种方式谈论它,那么可以肯定地说 thread.start() 永远无法重新排序。

就被称为开始的线程而言,就好像到那一点之前的一切都是顺序的。例如说我们有

int k = 8;
new Thread(() -> {}).start()

现在...无论是首先调用 start 还是将 k 分配给 8,从该线程的角度来看都没有区别。所以这可以重新排序,但是由于发生在保证之前,这是不可能的?

java 规范并没有明确说明这一点。而是说

当语句调用 Thread.start() 时,与该语句具有先行关系的每个语句

但是 k = 8 并不表示 a happens before relationship with that statement...

我什至不确定它们是什么意思,在与启动方法的关系之前发生了一些事情,除非你使用同一个监视器锁定,例如

synchronized(this){ int k = 8;}
 synchronized(this) { new Thread(() -> {}).start();}

对于更可怕的情况,我们有这段代码

Socket con = socket.accept();
Runnable r = new Runnable(){ 
  public void run(){
      handleRequest(con)}
 }
new Thread(r).start();

然后新线程恰好发现 con 为空?

有人可以就这些话题给我一个明确的答案吗?

Would the program be guaranteed to print 5 since z happened before thread.start?

如果 z 的值是由调用 start() 方法的线程设置的,则可以。否则,不。新启动的线程保证看到启动它的线程所做的更改,而不是其他线程所做的更改。

Also if we talk about it in way, then is it safe to say that thread.start() can never be reordered ever.

关键是 - 保证新启动的线程将 k 的值视为 8。如果新启动的线程不读取 k(或父线程设置的任何其他变量),则允许编译器重新排序这样的操作,但对程序员来说无关紧要(反正程序员得到了保证)

And then the new thread happens to find that con to be null?

假设新线程有对con的引用,con保证在新线程启动之前被初始化(因为JMM保证父线程在调用start()之前所做的任何更改都是可见的到新线程)

总而言之 - 如果一个线程 (T1) 启动另一个线程 (T2),则 T1 在启动 T2 之前所做的任何更改都保证对 T2 可见。作为程序员,这才是最重要的。只要不违反此保证,编译器就可以执行重新排序。您当然可以参考 JLS,但我想您已经有了。