2016-08-01 88 views
4

考虑从书中Java并发实践由Joshua布洛赫拍摄的片段 -保证首先执行的指令/声明会先执行吗?

public class NoVisibility{ 
    private static boolean ready; 
    private static int number; 

    private static class ReaderThread extends Thread{ 
     public void run(){ 
      while(!ready) 
       Thread.yield(); 
      System.out.println(number); 
     } 
    } 

    public static void main(String[] args){ 
     new ReaderThread().start(); 
     number = 42;       // Statement 1 
     ready = true;       // Statement 2 
    } 
} 

对于主要线程由JVM启动,是它保证声明1将要执行的在陈述2之前。

我完全理解ReaderThread可能无法看到上面两个静态变量的更新值。我没有要求解决方案。但是,如果语句1在语句2之前执行,ReaderThread仍然可以看到准备好的更新值 &不适用于号码?这是什么重新排序意味着一般?


在同一本书的页面底部的段落揭示了一个洞察到这 -

没有在一个线程操作将在由给定的顺序执行 保证程序,只要重新排序不是 即可在该线程内检测到,即使重新排序对其他线程显然为 。

有点混乱这里 -

作者是只要重新排序是不是从那个线程中检测到的说... ...而在同一时间,他says-

- 即使重新排序对其他线程显而易见(清晰可见)。

如果在的情况下,重新排序是其他线程清晰可见,为什么他在同一时间“只要重新排序,未检出从该线程内”说什么? 如果重新排序是可见的,那意味着它也是可检测的。不是吗?

+0

*“是” *的语句在你的裁定,并为您的第二个问题执行:http://stackoverflow.com/a/16629365/351861 – specializt

+1

你可以找到一个很好的例子[这里](HTTP: //jeremymanson.blogspot.de/2007/08/atomicity-visibility-and-ordering.html)。所以是的,这是可能的。 –

+1

“在该线程内不可检测”表示*与当前代码*无法检测到。例如像'foo = 1; sleep_ten_minutes(); foo = 2;''''''''''''''''''''''''''''''可以从开始就设置foo = 2,因为它在执行线程中检测不到(不检查值),但其他线程在10分钟之前会看到foo == 2。 – alzee

回答

2

这并不能保证一般。此外,更新发生不能保证,因为没有volatile被添加到其中一个字段。这将同步线程的缓存,并保证顺序。

(我希望我是正确的。)


澄清(我希望)

给定的情况下不作为备受关注的Java字节码由JVM处理。 (一般来说)不是编译器巧妙地重新排列或解释乱序的字节码。它是在一个线程中运行的即时编译代码,具有本地线程缓存,重复地保存公共变量。

易失性标记字段确保这些公共变量与所有线程同步。当然,只要结果没问题,单个线程可以按任意顺序执行代码。

y = ++x; 

pseudoassembly

1. move from @x to register1 
2. increment register1 
3. move from register1 to @x 
4. move from register1 to @y 
5. synchronize @x and @y 

以下的实际执行可能完全不同在不同的处理器来完成。一个或两个变量可能会被缓存在线程内存本身,或者需要写入远端变量,或者不需要。

当然,保证同一个线程处理得到正确的结果。没有人看到,顺序是无关紧要的:由于记忆,4可能在3之前或比3快。

如果3.和4.是JIT编译切换,相同的线程不会看到/检测到任何差异,但其他线程可能会首先看到y的变化。那没有volatile

这一切都相当深奥,太低级。有人可能会奇怪它是在语言规范中出现的,就像byte变量在内部存储为4字节字。它处理实现问题,确实是相关的,比如丢失字节操作。当对这个主题感兴趣时,可以拿一个汇编程序,也许把它和C结合起来,然后再尝试这些东西。否则,请远离不安全的编程。

+0

恩....执行顺序**是**保证。确实 - 但只在**当前**线程内,另一个线程可能会“看到”*不同的东西:http://stackoverflow.com/a/16629365/351861。请不要写出你不确定的答案 – specializt

+2

@specializt JIT编译器和CPU可以自由地重新排列这些语句。没有什么可以阻止,也不希望它。 –

+0

...只有当重新排序“产生符合法律执行的结果” - 所以它实际上并不重要,重新排序本身是一个实现细节,一致的结果是保证 - 在同一个线程内。 – specializt

相关问题