Java 为什么这个程序在无限循环中运行?互斥
下面是我开始学习互斥的java程序Java 为什么这个程序在无限循环中运行?互斥,java,multithreading,scheduler,mutual-exclusion,Java,Multithreading,Scheduler,Mutual Exclusion,下面是我开始学习互斥的java程序 class MutexVar{ public static int Turn = 1; } class CriticalSection{ private static int modelNumber =0; public static void setModelNumber(int number){ modelNumber = number; } public static int getModelN
class MutexVar{
public static int Turn = 1;
}
class CriticalSection{
private static int modelNumber =0;
public static void setModelNumber(int number){
modelNumber = number;
}
public static int getModelNumber(){
return modelNumber;
}
}
public class MutualExclusion{
public static void main(String[] args){
Thread threadObjRef = new Thread(new Runnable(){
public void run(){
int autoVar = 1;
int newModelNumber = -1;
while(true){
/* Non - critical section - start */
System.out.println("\n" + "In run() thread");
/* Non - critical section - end */
while(MutexVar.Turn == 2){
//System.out.println("loop-run"); //infinite loop problem is here
}
/* Critical Section -start */
CriticalSection.setModelNumber(autoVar);
newModelNumber = CriticalSection.getModelNumber();
MutexVar.Turn = 2;
/* Critical Section -end */
/* Non - critical section - start */
System.out.println("run() thread: " + newModelNumber + "\n");
autoVar = autoVar + 2;
/* Non - critical section - end */
}
}
});
threadObjRef.start();
int autoVar = 0;
int newModelNumber = -1;
while(true){
/* Non - critical section - start */
System.out.println("\n" + "In main thread");
/* Non - critical section - end */
while(MutexVar.Turn == 1){
//System.out.println("loop-main"); //infinite loop problem is here
}
/* Critical Section -start */
CriticalSection.setModelNumber(autoVar);
newModelNumber = CriticalSection.getModelNumber();
MutexVar.Turn = 1;
/* Critical Section -end */
/* Non - critical section - start */
System.out.println("main- thread: " + newModelNumber + "\n");
autoVar = autoVar + 2;
/* Non - critical section - end */
}
}
}
我的问题:
1) 设置MutexVar.Turn
的两个线程之间是否存在数据竞争
2) 如果没有,那么这个程序对我来说很好,但是我的程序无限循环,输出如下。为什么无限循环循环运行
或循环主循环
In main thread
In run() thread
run() thread: 1
In run() thread
我的观察:
这看起来像是线程调度问题。我了解到java线程对windows操作系统是可见的,因为它们是在内部使用
kernel32.dll的CreateThread()
api创建的,并由操作系统在windows中作为1-1线程模型进行调度。java程序在Windows7多核操作系统上使用JavaJDK1.6运行 一开始你的代码读错了。看起来您有一个过时的值
MutexVar.Turn
s值不会刷新,以便其他线程看到最新的更改。如果在读取和写入线程之间共享的公共变量时,将Turn
更改为在某个公共锁上声明为volatile或synchronized,那么您可能会发现MutexVar。将s值更改。始终同步对共享可变数据的访问。JIT/CPU正在做什么并不十分明显,但通过使用非易失性Turn
,您几乎肯定会遇到线程缓存问题。将MutrexVar
声明为
static class MutexVar {
public static volatile int Turn = 1;
}
关键字Volatile表示,读取此值的每个线程都将具有最新的值,并禁止编译器重新排序
编译器重新排序的更多细节。JIT编译器能够读取您的代码并提升对Turn
的读取。例如,它可以转换
while(MutexVar.Turn == 1){
//System.out.println("loop-main"); //infinite loop problem is here
}
进入
这绝不会违反Java的编译器契约,并且可以显著提高性能。声明字段volatile可防止此类型或重新排序。为什么操作系统不在两个线程之间交错?我想这是我想理解的一点。用某种特定语言编写的程序不可能成为问题。在后台,Java可以缓存值,只要它不违反线程内语义(程序顺序)。操作系统所做的正是JIT将代码编译成的。是的,它在设置为volatile
后工作。但是,如果我比较字节码,两种情况下都是一样的。在run()线程中,它是:Line#31 getstatic 41;/*MutexVar.Turn*/
在main()线程中是:行MutexVar.Turn*/
尽管我使用了volatile
关键字yes!字节码最初通过编译源代码生成一次。您希望看到的是在程序集运行时生成的程序集。初始编译通常是非操作化的。JIT在运行时需要更多关于如何更改它的信息。看看通过-XX:+UnlockDiagnosticVMOptions-XX:+PrintAssembly
启用程序集输出它,我想,.java
被编译成.class
,然后JVM逐个指令解释.class
指令。不是吗?JIT是在哪个阶段出现的?是的,它与volatile
一起工作,但是当我们声明volatile时,到底发生了什么。因为main(){}
的字节码看起来与我相似,带有/不带volatile关键字。有没有出现这个问题,,如果这个程序是用C/C++?@overexchange编写的,那么Java编程语言指定,如果没有用于在线程之间共享可变状态的适当同步工具,JVM可以自由地进行优化,从缓存值到刷新值到RAM,再到重新排序语句,因为它假定数据不可用如果使用volatile/synchronized标记,则在线程之间共享。字节码可能不会有太大的变化,这里或那里可能有一两个标志,您将看到的真正区别是JVM编译(JIT)字节码时的实际程序集。@overexchange您可以使用此问题中提到的编译器标志来查看JVM编译字节码时的程序集输出:。我对c/c++不太熟悉,但我的理解是,这些语言规范没有指定线程之间共享状态的行为方式,因此这可能取决于编译器实现和您使用的线程库(您可能仍然需要进行某种刷新/锁定组合).@overexchange还可以使用-Xcomp标志,确保JVM在第一次使用时编译您的字节码,以便您可以看到输出。@overexchange这是一项功能。本质上,如果您没有将一个值标记为可能被多个线程使用(通过使用公共同步锁读取和写入该值,或将其声明为volatile),JVM可以进行优化,从对语句重新排序到在CPU缓存中保留一个值,并在经常使用的情况下对其进行修改(与每次将最新值写回主内存不同。如果最新值在某种缓存中停留了一段时间,而其他线程看不到,那么这些线程将认为它是过时的值)。
if(MutexVar.Turn == 1) {
while(true) {
//System.out.println("loop-main"); //infinite loop problem is here
}
}