由于同步顺序,以下 Java 程序是否必须打印"num:1 m_i:2 "



我只是想检查一下我对JMM的线程启动同步规则的理解是否正确:

是否仅仅因为下面的同步顺序,下面的Java程序必须打印"num:1 m_i:2 " ?

http://java.sun.com/docs/books/jls/third_edition/html/memory.html 17.4.4


启动一个线程的动作与它启动的线程中的第一个动作同步。

public class ThreadHappenBefore {
    static int num;
    int m_i;
    public static void main(String[] args) {
        final ThreadHappenBefore hb = new ThreadHappenBefore();
        num = 1;
            hb.m_i = 2;
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("num:"+num);
                System.out.println("m_i:"+hb.m_i);
            }
        }).start();
    }
}

在给定线程中,如果前面的代码对后面的代码有影响,则保证其他代码之前编写。因为线程开始在赋值之后被编码为和赋值影响 print语句的结果,这些赋值对于打印它们的代码是"可见的"(即发生在它们之前)。

但是,当从另一个线程查看时,对执行顺序的效果没有这样的保证

EDITED(感谢评论)

对上面的重新排序进行了细化(粗体)

我不认为你这里有同步问题由于代码顺序,您将得到您期望的结果。如果有多个线程引用相同的源

,则可能发生同步问题。

到目前为止,除了Stephen C在评论中发表了正确的答案:线程的创建(start()而不是new thread()!)确保了happens-before关系。

如果不是这种情况,JVM可以很容易地重新排序指令,只要它能保证自己的线程不会看到差异。

可以肯定的是,在每一种具有合理多线程内存模型的语言中,对于这种情况都会有一些内存障碍,因为否则你无法可靠地将参数传递给线程。

不,由于17.4.5节中的"happens-before"关系,它打印了正确的内容。如果你看下一节的讨论,它也清楚地说明:

线程上的start()调用发生在线程中的任何操作之前启动线程。

而且:

如果x和y是同一个线程的动作,并且x在y之前程序顺序,然后hb(x, y)。

因此这两个赋值保证发生在线程的读操作之前。

您的示例中没有同步

什么 '同步顺序'?这里没有同步。这只是普通的执行命令。所有的赋值都发生在线程启动之前。

最新更新