为什么这个程序会无限循环运行?互斥
Why this program runs in infinite loop? 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 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) 如果不是,那么这个程序对我来说看起来不错,但是我的程序会无限循环,输出如下。为什么无限循环 loop-run
或 loop-main
?
In main thread
In run() thread
run() thread: 1
In run() thread
我的观察:
这看起来像是线程调度问题。我了解到 java 线程对 windows OS 可见,因为它们是使用 kernel32.dll
的 CreateThread()
api 在内部创建并由 [=38 调度=] 作为 windows 中的 1-1 线程模型。 java 程序在 windows 7 多核 OS 上使用 java jdk 1.6 运行。
一开始读错了你的代码。看起来你有一个过时的值。
MutexVar.Turn
s 值永远不会被刷新以供其他线程查看最新更改。如果在读取和写入线程间共享的公共变量时将 Turn
更改为声明为 volatile 或在某个公共锁上同步,那么您可能会发现 MutexVar.Turn
的值要更改。
始终 同步对共享可变数据的访问。 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
}
进入
if(MutexVar.Turn == 1) {
while(true) {
//System.out.println("loop-main"); //infinite loop problem is here
}
}
这绝不会违反 Java 的编译器契约,并且可以显着提高性能。将字段声明为 volatile 可防止此类型或重新排序。
下面是我开始学习互斥的 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 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) 如果不是,那么这个程序对我来说看起来不错,但是我的程序会无限循环,输出如下。为什么无限循环 loop-run
或 loop-main
?
In main thread
In run() thread
run() thread: 1
In run() thread
我的观察:
这看起来像是线程调度问题。我了解到 java 线程对 windows OS 可见,因为它们是使用 kernel32.dll
的 CreateThread()
api 在内部创建并由 [=38 调度=] 作为 windows 中的 1-1 线程模型。 java 程序在 windows 7 多核 OS 上使用 java jdk 1.6 运行。
一开始读错了你的代码。看起来你有一个过时的值。
MutexVar.Turn
s 值永远不会被刷新以供其他线程查看最新更改。如果在读取和写入线程间共享的公共变量时将 Turn
更改为声明为 volatile 或在某个公共锁上同步,那么您可能会发现 MutexVar.Turn
的值要更改。
始终 同步对共享可变数据的访问。 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
}
进入
if(MutexVar.Turn == 1) {
while(true) {
//System.out.println("loop-main"); //infinite loop problem is here
}
}
这绝不会违反 Java 的编译器契约,并且可以显着提高性能。将字段声明为 volatile 可防止此类型或重新排序。