现在已经有很好的答案已经在stackoverflow上,但他们没有给我我想要的明确答案。
假设您有方法
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,都不会有所不同。所以这可以重新排序,但是由于在保证之前发生了,这是不可能的吗? / p>
java规范没有说明这一点的强烈声明。相反,它说
当一个语句调用Thread.start()时,每个与该语句具有先前发生关系的语句
然而,k = 8并不是在与该陈述的关系之前发生的......
我甚至不确定他们的意思是在与start方法的关系之前发生了什么事情,除非您使用相同的监视器锁定例如
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为null?
有人可以就这些主题给我一个明确的答案吗?
答案 0 :(得分:4)
程序是否可以保证打印5,因为z发生在thread.start之前?
如果z的值由调用start()方法的线程设置,则为yes。否则,没有。新启动的线程可以保证看到启动它的线程所做的更改,而不是其他线程所做的更改。
另外,如果我们以某种方式谈论它,那么可以肯定地说,thread.start()永远不会被重新排序。
关键是 - 新启动的线程保证看到k的值为8.如果新启动的线程不读取k(或父线程设置的任何其他变量),则允许编译器重新启动对这样的操作进行排序,但对程序员来说无关紧要(程序员无论如何都得到了保证)
然后新线程碰巧发现con为null?
假设新线程具有对con的引用,则保证在新线程启动之前初始化con(因为JMM保证在调用start()之前父线程所做的任何更改对于新线程)
总结 - 是一个线程(T1)启动另一个线程(T2),然后在开始T2之前由T1做出的任何更改都保证对T2可见。作为程序员,这才是最重要的。只要不破坏此保证,编译器就可以执行重新排序。你当然可以参考JLS,但我认为你已经有了。