是否保证首先执行其他/ s之前的指令/声明?

时间:2016-08-01 08:29:43

标签: java

考虑一下摘自 Joshua Bloch实践中的Java Concurrency -

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是否仍然可以看到 ready &的更新值。不是数字?这是重新排序一般意味着什么?

同一本书页面底部的一个段落揭示了对此的见解 -

  

无法保证将在一个线程中执行操作   按程序给出的顺序,只要重新排序不是   可以从该线程中检测到 - 即使重新排序是明显的   到其他线程。

这里有点混乱 -

作者说... 只要在该线程中无法检测到重新排序...... 同时,他说 -

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

如果以防万一,重新排序对其他线程清晰可见,他为什么同时说“只要在该线程内无法检测到重新排序”如果重新排序可见,则表示它也可以检测到。不是吗?

1 个答案:

答案 0 :(得分:2)

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

(我希望我是对的。)

澄清(我希望)

给定的场景并不像jvm处理的java字节码那么重要。 (通常)不是这样编译器巧妙地重新排列或解释字节代码。它是在具有本地线程缓存的线程中运行的即时编译代码,重复地保存公共变量。

volatile标记字段可确保将这些公共变量同步到所有线程。当然,只要结果合适,单个线程就可以按任何顺序执行代码。

y = ++x;

以下伪装配的实际执行

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

可能在不同的处理器上完全不同。一个或两个变量可能会缓存在线程内存本身中,或者需要写入far变量,或者不需要。

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

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

  

这一切都非常深奥,太低级了。有人可能会想到它出现在语言规范中,就像byte变量在内部存储在一个4字节字中一样。它处理实现问题,确实是相关的,比如缺少字节操作。当一个人对这个主题感兴趣时,拿一个汇编程序,也许和C结合起来试试这些东西吧。否则远离不安全的编程。