2016-12-11 1 views
2

프로그래머가 동기화에 사용 된 변수에 volatile 키워드를 추가하는 것을 잊어 버린 경우 캐시 시점 (MESI 프로토콜)에서 어떤 일이 발생하는지 알고 싶습니다.휘발성 변수가없는 깨진 동기화

다음 코드 스 니펫은 일부 반복 후에는 단순히 멈 춥니 다. 두 스레드 중 하나 (THREAD 0을 가정 해 봅시다)가 current에 대한 업데이트를 getNext()에 의해 THREAD 1에 의해 수행 된 것을 보지 못하기 때문에 그것이 영원히 계속 반복되는 것을 알고 있습니다.

그러나 나는 왜 그런지 이해하지 못합니다. THREAD 0은 current에서 루핑되고 어느 시점에서 캐시 라인이 THREAD 1 (캐시 라인이 수정 됨 상태로 전환 됨)에 의해 업데이트되고 메모리 캐시에서 로컬 캐시에서 패치를 가져 오는 "읽기"메시지를 표시해야합니다. 변수 currentvolatile 수정자를 추가하면 모든 것이 잘 작동합니다.

THREAD 0의 실행이 계속되는 것을 방지하는 어떤 현상이 발생합니까?

참조 : Memory Barriers: a Hardware View for Software Hackers

public class Volatile { 
    public static final int THREAD_0 = 0; 
    public static final int THREAD_1 = 1; 
    public static int current; 
    public static int counter = 0; 

    public static void main(String[] args) { 
     current = 0; 

     /** Thread 0 **/ 
     Thread thread0 = new Thread(() -> { 
      while(true) { /** THREAD_0 */ 
       while (current != THREAD_0); 

       counter++; 
       System.out.println("Thread0:" + counter); 

       current = getNext(THREAD_0); 
      } 
     }); 

     /** Thread 1 **/ 
     Thread thread1 = new Thread(() -> { 
      while(true) { /** THREAD_1 */ 
       while (current != THREAD_1); 

       counter++; 
       System.out.println("Thread1:" + counter); 

       current = getNext(THREAD_1); 
      } 
     }); 

     thread0.start(); 
     thread1.start(); 
    } 

    public static int getNext(int threadId) { 
     return threadId == THREAD_0 ? THREAD_1 : THREAD_0; 
    } 
} 

답변

0

다른 프로세서 아키텍처는 캐시 일관성의 다른 학위를 가지고 있습니다. 처리량을 최대화하고 불필요하게 메모리가있는 캐시를 동기화하는 것이 목표이기 때문에 일부는 매우 미미할 수 있습니다. Java는 조정이 필요하다는 것을 감지하면 자체 메모리 장벽을 부과합니다. 그러나 규칙을 따르는 프로그래머에 따라 다릅니다.

변수가 스레드간에 공유 될 수 있다는 표시를 프로그래머가 추가하지 않으면 (JIT는 다른 스레드가 해당 변수를 수정하지 않는다고 가정하고 그에 따라 최적화 할 수 있습니다) . 그 변수를 테스트하는 바이트 코드는 재 배열 될 수 있습니다. JIT가 코드를 재 배열하면 하드웨어가 수정을 감지하고 새로운 값을 가져 오는 것이 중요하지 않을 수 있습니다. 연습 3.1에서 자바 동시성에서 인용

: 동기화가없는

는, 컴파일러, 프로세서 및 런타임 작업을 실행하기 위해 표시되는 순서에 약간의 솔직한 이상한 일을 할 수있다. 불충분하게 동기화 된 멀티 스레드 프로그램에서 메모리 동작이 "반드시"발생해야하는 순서를 추론하려는 시도는 거의 틀린 것입니다.

은 (충분히 동기화 코드에 대해 추론하는 것은 무의미하다 케이스를 만드는 JCIP 책의 여러 곳이 있습니다.)

당신은 완전히 맞아
+1

,이 문제는 JIT 컴파일러와 관련이 있습니다. 해석 모드 (-Xint)에서만 프로그램을 시작하면 컴파일 된 모드 (-Xcomp)에서는 작동하지 않지만 영원히 작동합니다. 이 답변을 주셔서 감사합니다! –

관련 문제