为什么这个程序在无限循环中运行?相互排斥

时间:2015-01-16 14:29:41

标签: 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 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

我的观察:

这看起来像是线程调度问题。我了解到Windows操作系统可以看到java线程,因为它们是使用CreateThread()的{​​{1}} api在内部创建的,并且由OS调度为Windows中的1-1线程模型。 java程序在Windows 7多核OS上使用java jdk 1.6运行。

3 个答案:

答案 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) {}