为什么这个程序会无限循环运行?互斥

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-runloop-main

In  main thread

In  run() thread
run() thread: 1


In  run() thread

我的观察:

这看起来像是线程调度问题。我了解到 java 线程对 windows OS 可见,因为它们是使用 kernel32.dllCreateThread() api 在内部创建并由 [=38 调度=] 作为 windows 中的 1-1 线程模型。 java 程序在 windows 7 多核 OS 上使用 java jdk 1.6 运行。

一开始读错了你的代码。看起来你有一个过时的值。

MutexVar.Turns 值永远不会被刷新以供其他线程查看最新更改。如果在读取和写入线程间共享的公共变量时将 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 可防止此类型或重新排序。