2

我是 Java 线程的新手,最近才开始阅读内存模型。根据我的理解,Java 内存模型允许编译器进行优化。

这可能会使多线程代码和同步变得复杂,但我的问题是要简单得多。举这个例子,因为这两个语句不相互依赖,编译器是否有可能改变 try 语句中代码的顺序,从而中断检查?

boolean success = false;
try{
 MyClass.someFunction();
 success = true;
}
catch(Exception e){

}

if(success){    
    System.out.println("Sucess!");
}
else{
    System.out.println("Fail!");
}
4

2 回答 2

4

不,Java 编译器需要执行您所期望的操作——Success!如果Myclass.someFunction()正常返回并且Fail!引发异常,则打印。这通常来自 Java 的语义,并且独立于您的编译器可能进行的任何编译器优化(除非它可能限制哪些优化是合法的)。

原因是 Java 语言规范规定,在单个线程中,程序的行为必须与语句完全按照从上到下的顺序执行一样。编译器可以自由地以各种不直观的方式重写您的程序以生成字节码,但它必须保持这样的错觉,即在单个线程中,它正在以正确的顺序运行您在源代码中键入的语句。

Java 语言规范也可以将其扩展到多线程上下文,并说每个线程必须始终看到与您的所有线程完全一致地执行您输入的源代码的世界状态。但是,(a) 那会使编写正确的编译器优化变得非常困难,并且许多其他有用的优化将是非法的;(b) 它不会对程序员有太大帮助,因为它无论如何都不会消除对正确同步的需要;它主要只是将损坏的程序变成不太明显的损坏程序。

相反,Java 内存模型定义了一个线程中的内存修改何时对其他线程可见的精确规则,并让编译器做它想做的其他事情。这是一个很好的折衷方案,因为它为程序员提供了一套规则,他们可以使用这些规则来确保他们的多线程程序是正确的,同时仍然给编译器编写者实现良好优化的余地。

但是您问题的重点是:编译器可以在幕后做任何事情,但不允许改变程序的含义。在单线程上下文中,您的程序的含义是明确定义的,并且不允许编译器做您认为它可以做的坏事。

于 2010-11-08T05:17:07.923 回答
2

由于 Java 无法理解做什么MyClass.someFunction(),它无法安全地重新排序此语句。事实上,由于副作用,大多数数据依赖性检查器完全无法移动到函数边界之外。

线程是一种特殊情况,并不是 Java 独有的——数据最终存储在寄存器中,除非需要,否则不会从内存中重新获取。Java 的解决方案是transient关键字(类似于volatile其他语言)。

于 2010-11-08T04:13:39.897 回答