2013-02-22 146 views
0

在Java中,C和C++是保证在单个给定线程内按顺序逐行执行的源代码,即使在编译器优化后也是如此。好像没有什么是不可能获得成功,如果系统被允许重新整理你的代码,但我似乎无法找到任何文件,以保证如果我在Java中的以下内容:在单个线程内执行Java代码是否保证顺序?

class MyClass{ 
String testString = ""; 

public MyClass(){ 

} 

public void foo(){ 
    testString = "foo"; 
} 
public void bar(){ 
    testString = "bar"; 
    testString += "r"; 
} 
public String getTestString(){ 
    return testString; 
} 

} 

class Main{ 
static void main(String[] args){ 
    MyClass testClass = new MyClass(); 
    testClass.foo(); 
    System.out.println(class.getTestString()); 
    testClass.bar(); 
    System.out.println(class.getTestString()); 
} 
} 

输出将永远是

"foo" 
"barr" 

和从未

"foo" 
"rbar" 

,或者如果内它们的方法调用和语句不是顺序地执行作为SPE可能出现的任何其它可能的变化在源代码中引用。

这个问题引发了Java的具体问题,因为它使得程序员对目标系统上的字节码编译器和JIT编译器或解释器将对您的代码执行的操作的控制明显减少。我所讨论的主要系统是Android,为此我实现了自己的信号量和互斥锁定机制(例如,不会过多地使用像'synchronized'和'volatile'这样的内置Java并发机制,它更适合于我的应用程序比Java提供的应用程序。然而,一位朋友警告我说,由于Java从源代码到机器代码的多重转换水平,除非我使用Java的内置并发机制,否则不能保证我的信号量和锁定实现将按我的意图执行。这真的归结为是否存在一个特定的保证,对于任何给定的运行时实现,代码的执行将在单个线程内连续执行。所以主要的问题是:

  1. 在C和C + +是代码执行保证顺序,尽管编译器优化?如果没有,是否足以实现这样的保证来禁用编译器优化?

  2. 在Java中,尽管潜在地改变了字节码编译器和JIT编译器或解释器(专门在Android上运行,但也适用于任意虚拟机实现),但是代码执行是保证顺序的?

  3. 如果上面的答案是肯定的,那么是否有任何编程语言/平台/上下文在单线程中的顺序执行不能保证?

+3

'在C和C++是执行代码保证是,尽管编译顺序优化?'你在那里开放了一整罐蠕虫... – BoBTFish 2013-02-22 15:48:58

+6

绝对不是。 [编译器很少编译你写的代码](http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-1-of-2)。 – 2013-02-22 15:49:16

+0

在单线程的过程中,您的方案将永远不会发生...... – 2013-02-22 15:50:26

回答

3

如果只有一个线程,您的代码将具有直观的预期结果。任何优化必须在优化之前保留功能。意想不到的事情只有当你有多个线程时才会发生。

基本符合当有多个线程,你的问题是关于如这里所定义的“线程内语义”即出现反直觉的行为

Java语言规范的交易:

存储模式决定了什么样的价值观可以在程序的每个点上读取。隔离的每个线程的行为必须像该线程的语义一样行为,除了每次读取的值由内存模型决定。当我们提到这个时,我们说程序服从于线程内部的语义。线程内语义是单线程程序的语义,并且允许基于线程内读取操作所看到的值完全预测线程的行为。为了确定执行过程中线程t的动作是否合法,我们简单地评估线程t的实现,因为它将在单线程上下文中执行,如本规范其余部分所定义。

http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html

1

是的,你上面提供的代码将被按顺序执行。即使有50个处理器,您的代码也会在一个线程上按顺序执行。

顺便说一句,很确定你不能调用一个变量类。即使你可以,也不要。

+0

呵呵,我的不好。在会议开始前的最后几秒钟就剔除了这个例子 – CCJ 2013-02-22 19:20:35

2

即使在没有螺纹大多数编译器被允许重新排序的代码,以获得最佳的速度,找到更多的答案。但重新排序的结果不允许影响结果。在C/C++中,这被称为as-if规则。

因此,在函数内,只要结果不受影响,编译器就可以重新排序进行优化。所以我们在“源代码”和“生成的代码”之间略有不同。

在线程代码中会有一个线程执行一个函数吗?这取决于你如何定义线程。什么是线程(一组堆栈帧/寄存器/和当前执行点)。

我看到移动核心之间的线程没有问题(虽然我可以看到为什么运行时不会想这样做,我不认为它是强制性的)。所以你不能假设线程不会跳转内核。但是,如果您认为“执行线程”是当前状态而不涉及任何硬件。

你可以保证的是,“执行线程”将从一段“生成的代码”的开始到结束执行。它不会遗漏任何“生成的代码”。它将按顺序执行“生成的代码”。如果不计划并重新计划,它将从其离开的地方继续。

1

我认为最简单的答案是编译器开发人员遵循“不应该修改单线程程序的行为”的口头禅,除此之外,我认为你是你自己的。

“preshing on programming”对我遇到的无序执行问题有一些最好的解释。如果有人知道我想知道的一组更好的文章。这里有两个人,但如果你真的想钻研它,你应该检查出更多的材料在网站上:

Memory Ordering at Compile Time
Weak vs. Strong Memory Models