2015-01-16 5 views
2

아래는 상호 배제에 대해 배우기 시작한 자바 프로그램입니다.이 프로그램이 무한 루프로 실행되는 이유는 무엇입니까? 상호 배제

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 

내 관찰 :

이 스레드 스케줄링 문제처럼 보인다. 나는 그들이 내부적으로 의 CreateThread() api를 사용하고 윈도우즈에서 1-1 스레딩 모델로 OS에 의해 스케줄되어지기 때문에 자바 쓰레드가 Windows OS에서 볼 수 있다는 것을 배웠다. 자바 프로그램은 Windows 7 멀티 코어 OS에서 java jdk 1.6을 사용하여 실행됩니다.

+0

OS가 두 스레드간에 인터리빙하지 않는 이유는 무엇입니까? 나는 이것이 내가 이해하고자하는 요점이라고 생각한다. 특정 언어로 작성된 프로그램은 문제가 될 수 없습니다. – overexchange

답변

3

항상 동기화 액세스를. JIT/CPU가 수행하는 작업이 정확히 무엇인지는 명확하지 않지만 비 휘발성 인 Turn을 사용하여 스레드 캐싱 문제를 거의 확실히 수행하고 있습니다. 이 값이 최신 값을가집니다 읽고 컴파일러 reorderings 금지 MutrexVar

static class MutexVar { public static volatile int Turn = 1; } 

키워드에 휘발성 말한다

등 각 스레드를 선언합니다.


좀 더 자세한 컴파일러 순서 재 지정. JIT 컴파일러는 코드를 가져 와서 Turn을 읽을 수 있습니다. 예를 들어이 어떠한 방식으로

if(MutexVar.Turn == 1) { 
    while(true) { 
     //System.out.println("loop-main"); //infinite loop problem is here 
    } 
} 

이에

while(MutexVar.Turn == 1){ 
    //System.out.println("loop-main"); //infinite loop problem is here 
} 

을 변환 할 수 있습니다 것은 자바 컴파일러 계약을 위반하고 성능을 크게 향상시킬 수 있습니다. 필드를 휘발성으로 선언하면이 유형이나 순서를 다시 지정할 수 없습니다.

+0

자바 스크립트는 내부 스레드 의미 (프로그램 순서)를 위반하지 않는 한 값을 캐시 할 수있다. 운영 체제는 JIT가 코드를 컴파일하는 작업을 정확하게 수행합니다. –

+0

예. '휘발성'으로 설정 한 후 작동 중입니다. 하지만 바이트 코드를 비교하면 두 경우 모두 같습니다. run() 쓰레드에서는 다음과 같습니다 :'Line # 31 getstatic 41;/* MutexVar.Turn * /'그리고 main() 쓰레드에서 : Line # 47 putstatic 41;/* MutexVar.Turn * /'휘발성 키워드 사용에도 불구하고 – overexchange

+0

예! 바이트 코드는 처음에 소스를 컴파일하여 생성됩니다. 당신이보고 싶은 것은 그것이 실행되는 동안 생성 된 어셈블리입니다. 초기 컴파일은 일반적으로 opotmized되지 않습니다. JIT는 런타임 중에이를 변경하는 방법에 대한 자세한 정보가 필요합니다. –

4

처음에는 코드를 잘못 읽었습니다. 부실 가치가있는 것 같습니다.

MutexVar.Turn 값이 다른 스레드에 대해 플러시되어 절대로 변경되지 않습니다. Turn을 volatile로 선언하거나 스레드간에 공유되는 공통 변수를 읽고 쓸 때 일부 공용 잠금에서 동기화되도록 변경하면 MutexVar.Turn 값이 변경 될 수 있습니다.

+0

예, '휘발성 (volatile)'과 함께 작동하지만 휘발성을 선언 할 때 정확히 무슨 일이 벌어지고 있는지.'main() {}'의 바이트 코드가 휘발성 키워드가있는 /없는 키워드와 비슷해 보입니다. 이 프로그램이 C/C++로 작성된 경우이 문제가 발생합니까? – overexchange

+0

@overexchange 자바 프로그래밍 언어는 적절한 동기 도구가 없으면 스레드간에 변경 가능한 상태를 공유하는 데 사용되므로 JVM이 값을 캐싱하여 RAM으로 플러시 한 후 데이터를 가정 할 때 명령문을 재정렬하기 전에 자유롭게 최적화 할 수 있도록 지정합니다 휘발성/동기화를 사용하는 것으로 표시되면 스레드간에 공유되지 않습니다. 바이트 코드가 그다지 변하지 않을 수도 있습니다. 아마 JIT가 바이트 코드를 컴파일 (JIT) 할 때 실제 어셈블리를 볼 수 있습니다. – NESPowerGlove

+0

@overexchange이 질문에서 언급 한 컴파일러 플래그를 사용하여 JVM이 바이트 코드를 컴파일 할 때의 어셈블리 출력을 볼 수 있습니다. http://stackoverflow.com/questions/1503479/how-to-see-jit-compiled-code- in-jvm. 나도 C/C++에 익숙하지 않지만 내 이해는 그 언어 스펙은 쓰레드 간의 공유 상태가 어떻게 동작해야 하는지를 지정하지 않기 때문에 아마도 컴파일러 구현과 사용하는 라이브러리 스레딩에 달려있다. flush/lock combo의 일종). – NESPowerGlove

-4

스레드에서 하드 루프를 실행하지 마십시오. 기껏해야 시스템 리소스를 낭비하고 다른 스레드를 잠글 수 있습니다. 당신의 동안은 다음이 포함되어야 MutexVar.Turn에 루프 : 공유 가변 데이터에

try { 
    Thread.sleep (10); 
} catch (InterruptedException e) {} 
+0

OP는 중요한 프로그램이 아닌 ** 학습 **을 위해이 프로그램을 사용하고 있습니다. – mbomb007

+0

왜 그런 말을합니까? 스레드가 시간을 포기하지 못하면 변수를 수정 한 후에도 스레드 실패의 원인이 될 수 있습니다. – gmcgath

+0

스레드에서 루핑하는 데는 아무런 문제가 없습니다. 무한 반복, 어쩌면,하지만 그것은 다른 대답에 의해 고려됩니다. 또한 게시자는 답변을 게시 할 가치가 있도록 충분한 설명을 간신히 넣었습니다. – mbomb007