以下是我开始学习互斥的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
我的观察:
这看起来像是线程调度问题。我了解到Windows操作系统可以看到java线程,因为它们是使用CreateThread()
的{{1}} api在内部创建的,并且由OS调度为Windows中的1-1线程模型。 java程序在Windows 7多核OS上使用java jdk 1.6运行。
答案 0 :(得分:4)
首先读错了你的代码。看起来你有一个陈旧的价值。
MutexVar.Turn
的值永远不会被其他线程刷新以查看最新的更改。如果您在读取和写入线程之间共享的公共变量时将Turn
更改为声明为volatile或在某些公共锁上同步,那么您可能会发现要更改的MutexVar.Turn
值。 / p>
答案 1 :(得分:3)
始终 同步对共享可变数据的访问权限。 JIT / CPU正在做什么并不是很明显,但是你几乎肯定会通过使用非易失性Turn
来解决线程缓存问题。将MutrexVar
声明为
static class MutexVar {
public static volatile int Turn = 1;
}
关键字上的易失性声明,读取此值的每个线程都将具有最新值并禁止编译器重新排序。
编译器重新排序的更多细节。 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会阻止此类型或重新排序。
答案 2 :(得分:-4)
你永远不应该在线程中运行硬循环;充其量,它浪费系统资源,它可能会锁定其他线程。 MutexVar.Turn上的while循环应该包含以下内容:
try {
Thread.sleep (10);
} catch (InterruptedException e) {}