2017-12-12 2 views
0

, 우리는 다음과 같은 코드Windows의 경쟁 조건을 가진 프로그램,하지만 우분투에서 경쟁 조건을 강조하기 위해 설계 과제에

public class IncreaseDecrease { 

    public static int IntegerVariable = 0; 
    public static final int NUM_ITER = 5000000; 

    public static void main(String[] args) throws Exception { 

     Increase inc; 
     Decrease dec; 

     while (true) {   
      inc = new Increase(); 
      dec = new Decrease(); 

      inc.start(); 
      dec.start(); 

      inc.join(); 
      dec.join(); 

      System.out.println(IntegerVariable); 
      IntegerVariable = 0; 
      Thread.sleep(750); 
     } 
    } 
} 

class Increase extends Thread { 

    @Override 
    public void run() { 
     for (int i = 0; i < IncreaseDecrease.NUM_ITER; i++) { 
      IncreaseDecrease.IntegerVariable++; 
     } 
    } 
} 

class Decrease extends Thread { 

    @Override 
    public void run() { 
     for (int i = 0; i < IncreaseDecrease.NUM_ITER; i++) { 
      IncreaseDecrease.IntegerVariable--; 
     } 
    } 
} 

각 스레드는 업데이트 할 수 있습니다 경우 0을 인쇄 할 것으로 예상된다이 코드를 받았다 없습니다 다른 값이 읽기 전에 값이 읽히지 만 경쟁 조건으로 인해 발생하지 않으면 -5000000에서 5000000 사이의 값을 인쇄 할 수 있습니다. Windows 및 repl.it에서이 코드를 실행하여 예상 출력을 얻었습니다. -310951 -1918567 -3374495 -3219135 -2286639 -3221055 -3794319 -2442047 -2776415 -3617391 하지만 우분투에서는 실행할 때마다 매번 0을주었습니다.

제 질문은 왜 이런 일입니까? 우분투는 스레드를 다르게 관리합니까, 아니면 내 컴퓨터의 특별한 경우입니까?

편집 : 다른 방법으로 증가분을 넣고 한 번 더 작업을 추가 한 후 경쟁 조건을 관찰했습니다.

public class IncreaseDecrease { 

    public static int IntegerVariable = 0; 
    public static final int NUM_ITER = 5000000; 

    public static void main(String[] args) throws Exception { 

     Increase inc; 
     Decrease dec; 

     while (true) {   
      inc = new Increase(); 
      dec = new Decrease(); 

      inc.start(); 
      dec.start(); 

      inc.join(); 
      dec.join(); 

      System.out.println(IntegerVariable); 
      IntegerVariable = 0; 
      Thread.sleep(750); 
     } 
    } 
    public static void increment() 
    { 
     IntegerVariable++; 
     double a = Math.pow(3, 7); 
    } 
    public static void decrement() 
    { 
     IntegerVariable--; 
     double a = Math.pow(3, 7); 
    } 
} 

class Increase extends Thread { 

    @Override 
    public void run() { 
     for (int i = 0; i < IncreaseDecrease.NUM_ITER; i++) { 
      IncreaseDecrease.increment(); 
     } 
    } 
} 

class Decrease extends Thread { 

    @Override 
    public void run() { 
     for (int i = 0; i < IncreaseDecrease.NUM_ITER; i++) { 
      IncreaseDecrease.decrement(); 
     } 
    } 
} 
+0

당신은 우분투로 부팅하거나 VirtualBox와 같은 VM에서 실행할 수 있습니까? 어쩌면 VM에서 단일 CPU 코어 만 할당 되었습니까? – user158037

+0

예. 난 하나의 코어와 VirtualBox에 우분투를 사용하고 있습니다. – mahdiou

+0

4 코어와 함께 사용하면 첫 번째 2 번의 반복에 대한 경쟁 조건이 나타 났지만 Simunov의 응답을 사용하여 코어 1 개를 사용해도 원하는 결과를 얻을 수있었습니다. – mahdiou

답변

1

나는 사지에 나가서 줄과 Windows에서하지 않는 동안 핫스팟이 리눅스에서 더 그럴듯한 설명은 서버 컴파일러입니다 사용한다고 주장 : 컴파일러는 단일로 전체 루프를 대체 할 수 있습니다 표현은 HotSpot이 확실히 할 수있는 것입니다. 모든 원시 메소드를 추가하면 불가능하므로 경쟁 조건을 훨씬 더 준수 할 수 있습니다.

이 경우도 마찬가지라고 생각합니다.

IntegerVariable volatile을 만들려고 했습니까? 이것은 발생할 수있는 일부 컴파일러 최적화를 방지합니다.

public static volatile int IntegerVariable = 0; 
+1

그냥 변수를 증가시키는 것보다 더 많은 작업을 수행 한 네이티브 메서드를 추가하여 경쟁 조건의 영향을 관찰 할 수있었습니다. 감사! 나는 또한 인용하고있는 기사에 대한 링크를 얻는 것을 좋아할 것이다. – mahdiou

+0

아래 답변에 대한 의견입니다. :) –

-1

그들이 진정하고 효율적으로 균일하게 처리를 인터리브 것을 자바 스레드에 대한 일반적인 오해가있다 : 여기에 최종 코드입니다. 실제로는 사실이 아니며 서로 다른 시스템의 다른 JVM은 다르게 작동합니다.

JVM이 스레드를 전환하기로 결정할 때 모두 발생합니다. JVM은 아마도 Thread.sleep()이나 블로킹 메소드 인 synchronized 또는 lock에 도달 할 때마다 스레드를 전환 할 것입니다. 그러나 일반적으로 스레드가 블로킹 등을 수행하지 않으면 스레드를 실행할 수 있습니다.

루프는 일시 중지없이 값을 증가 및 감소시킬 때 회전합니다. 루프에 Thread.sleep(0) 호출을 추가하면 JVM에서 스레드를/밖으로 전환 할 수있는 더 많은 기회를 제공하므로 차이가 발생할 수 있습니다.

for (int i = 0; i < IncreaseDecrease.NUM_ITER; i++) { 
     IncreaseDecrease.IntegerVariable--; 
     // Add this. 
     Thread.sleep(0); 
    } 
+1

또한,'Thread.sleep (0)'대신'Thread.yield()'를 사용할 수도 있습니다. – devpuh

+0

오해의 소지가 있습니다. 현대의 JVM은 그린 쓰레드를 사용하지 않으며, 모든 쓰레드는 네이티브 쓰레드를 사용한다. 결과적으로 Thread.Sleep이 컨텍스트 전환을 일으키는 지 여부는 기본 syscall의 구현 세부 사항입니다. – Voo

+0

필자는 사지에 서서 리눅스에서 서버 컴파일러를 사용하는 핫스팟을 Windows에서 사용하지 않는 동안 더 많은 가능성있는 설명이라고 주장한다. 컴파일러는 전체 루프를 핫 스폿이 확실한 단일 표현식으로 바꿀 수있다. 가능하다. 모든 고유 메소드를 추가하면 불가능하기 때문에 경쟁 조건을 훨씬 더 쉽게 관찰 할 수 있습니다. – Voo

관련 문제