>  기사  >  Java  >  Java 메모리 모델 심층 분석: 재정렬

Java 메모리 모델 심층 분석: 재정렬

黄舟
黄舟원래의
2016-12-29 12:01:151341검색

데이터 종속성두 작업이 동일한 변수에 액세스하고 두 작업 중 하나가 쓰기 작업인 경우 두 작업 간에 데이터 종속성이 있습니다. 데이터 종속성은 다음 세 가지 유형으로 나뉩니다. 이름코드 예시설명쓰기 후 읽기a = 1;b = a;변수를 쓴 후 이 내용을 읽어보세요. 위치 . 쓰기 후 쓰기a = 1;a = 2;변수를 쓴 후 이 변수를 다시 씁니다. 읽은 후 쓰기a = b;b = 1;변수를 읽은 후 다시 변수를 씁니다. 위의 세 가지 경우에서 두 작업의 실행 순서가 바뀌면 프로그램의 실행 결과가 변경됩니다. 앞서 언급했듯이 컴파일러와 프로세서는 작업 순서를 변경할 수 있습니다. 컴파일러와 프로세서는 순서를 변경할 때 데이터 종속성을 존중하며, 컴파일러와 프로세서는 데이터 종속성이 있는 두 작업의 실행 순서를 변경하지 않습니다. 여기에 언급된 데이터 종속성은 단일 프로세서에서 실행되는 명령 순서만을 참조하며, 서로 다른 프로세서와 서로 다른 스레드 사이의 데이터 종속성은 컴파일되지 않습니다. as-if-serial 의미as-if-serial 의미는 다음을 의미합니다. 어떻게 순서를 바꾸더라도(병렬성을 향상하기 위한 컴파일러 및 프로세서), (단일 스레드) 프로그램은 실행 결과는 변경할 수 없습니다. 컴파일러, 런타임 및 프로세서는 모두 직렬형 의미 체계를 준수해야 합니다. as-if-serial 의미 체계를 준수하기 위해 컴파일러와 프로세서는 데이터 종속성이 있는 작업의 순서를 변경하지 않습니다. 이러한 순서 변경으로 인해 실행 결과가 변경되기 때문입니다. 그러나 작업 간에 데이터 종속성이 없는 경우 이러한 작업은 컴파일러와 프로세서에 의해 재정렬될 수 있습니다. 구체적으로 설명하려면 원의 면적을 계산하는 다음 코드 예제를 살펴보십시오. 위 세 가지 작업의 데이터 종속성은 다음과 같습니다. 위 그림과 같이 A와 C 사이에도 데이터 의존 관계가 있고, B와 C 사이에도 데이터 의존 관계가 있습니다. 따라서 최종적으로 실행되는 명령어 시퀀스에서는 C가 A, B 앞에 위치하도록 재정렬할 수 없습니다. (C가 A, B 앞에 위치하므로 프로그램 결과가 변경됩니다.) 그러나 A와 B 사이에는 데이터 종속성이 없으며 컴파일러와 프로세서는 A와 B 사이의 실행 순서를 재정렬할 수 있습니다. 다음 그림은 프로그램의 두 가지 실행 순서를 보여줍니다. as-if-serial 의미론은 단일 스레드 프로그램을 보호하고 다음을 준수합니다. 컴파일러, 런타임 및 프로세서의 마치 직렬 의미 체계는 함께 작동하여 단일 스레드 프로그램을 작성하는 프로그래머에게 단일 스레드 프로그램이 프로그램 순서대로 실행된다는 착각을 불러일으킵니다. as-if-serial 의미론은 단일 스레드 프로그래머가 재정렬로 인한 간섭에 대해 걱정할 필요가 없고 메모리 가시성 문제에 대해 걱정할 필요도 없습니다. 프로그램 순서 규칙원의 면적을 계산하기 위한 위의 예제 코드에는 이전 발생 프로그램 순서 규칙에 따라 세 가지 이전 발생 관계가 있습니다. A 발생 - B 전;B 발생- C 전; A 발생- C 전 여기서 세 번째 발생 전 관계는 발생 전의 전이성을 기반으로 도출됩니다. 여기서 A는 B보다 먼저 발생하지만 실제 실행에서는 B가 A보다 먼저 실행될 수 있습니다(위의 재정렬된 실행 순서 참조). 1장에서 언급했듯이 A가 B보다 먼저 발생하면 JMM에서는 A가 B보다 먼저 실행되어야 한다고 요구하지 않습니다. JMM에서는 이전 작업(실행 결과)이 다음 작업에 표시되고 이전 작업이 두 번째 작업보다 순서대로 선행해야 합니다. 여기서 작업 A의 실행 결과는 작업 B에 표시될 필요가 없으며 작업 A와 작업 B를 재정렬한 후의 실행 결과는 작업 A와 작업 B를 발생 이전 순서로 실행한 결과와 일치합니다. 이 경우 JMM은 이러한 재정렬이 불법이 아닌 것으로 간주하여 JMM이 이러한 재정렬을 허용합니다. 컴퓨터에서 소프트웨어 기술과 하드웨어 기술은 프로그램의 실행 결과를 변경하지 않고 최대한 많은 병렬성을 개발한다는 공통 목표를 가지고 있습니다. 컴파일러와 프로세서는 이전 발생의 정의를 통해 JMM도 이 목표를 준수한다는 것을 알 수 있습니다. 재순서가 멀티스레딩에 미치는 영향이제 재정렬이 멀티스레드 프로그램의 실행 결과를 변경하는지 살펴보겠습니다. 아래 샘플 코드를 봐주세요. 플래그 변수는 변수 a가 작성되었는지 식별하는 데 사용되는 플래그입니다. 여기에서는 두 개의 스레드 A와 B가 있다고 가정합니다. A는 먼저writer() 메서드를 실행하고 B 스레드는 reader() 메서드를 실행합니다. 스레드 B가 작업 4를 수행할 때 스레드 A가 작업 1에서 공유 변수 a에 쓰는 것을 볼 수 있습니까? 답은 '꼭 눈에 보이는 것은 아닙니다'입니다. 작업 1과 작업 2에는 데이터 종속성이 없으므로 컴파일러와 프로세서는 이 두 작업의 순서를 변경할 수 있습니다. 마찬가지로 작업 3과 작업 4에는 데이터 종속성이 없으므로 컴파일러와 프로세서에서 이 두 작업의 순서를 변경할 수 있습니다. 먼저 작업 1과 작업 2의 순서가 변경되면 어떤 일이 발생할 수 있는지 살펴보겠습니다. 아래 프로그램 실행 타이밍 다이어그램을 살펴보세요. 위 그림과 같이 1번 작업과 2번 작업의 순서가 바뀌었습니다. 프로그램이 실행될 때 스레드 A는 먼저 플래그 변수 flag를 쓴 다음 스레드 B가 이 변수를 읽습니다. 조건이 true이므로 스레드 B는 변수 a를 읽습니다. 이때 변수 a는 스레드 A에 의해 전혀 작성되지 않았으며 여기서 멀티 스레드 프로그램의 의미는 재정렬로 인해 파괴됩니다! ※참고: 이 기사에서는 빨간색 점선 화살표를 사용하여 잘못된 읽기 작업을 나타내고 녹색 점선 화살표를 사용하여 올바른 읽기 작업을 나타냅니다. 작업 3과 4가 재정렬되면 어떤 일이 발생하는지 살펴보겠습니다(이 재정렬을 통해 제어 종속성도 설명할 수 있습니다). 다음은 작업 3과 4가 재정렬된 후 프로그램의 실행 타이밍 다이어그램입니다. 프로그램에서는 동작 3과 동작 4 사이에 제어 의존성이 존재합니다. 코드에 제어 종속성이 있으면 명령 시퀀스 실행의 병렬성 정도에 영향을 미칩니다. 이를 위해 컴파일러와 프로세서는 추측 실행을 사용하여 제어 종속성이 병렬성에 미치는 영향을 극복합니다. 프로세서의 추측 실행을 예로 들면, 스레드 B를 실행하는 프로세서는 미리 a*a를 읽고 계산한 다음, 계산 결과를 재정렬 버퍼 ROB라는 하드웨어 캐시에 임시 저장할 수 있습니다. 다음 연산 3의 조건이 참이라고 판단되면, 계산 결과가 변수 i에 쓰여진다. 그림에서 추측 실행은 기본적으로 작업 3과 4의 순서를 변경한다는 것을 알 수 있습니다. 여기서 순서를 바꾸면 다중 스레드 프로그램의 의미가 깨집니다! 단일 스레드 프로그램에서 제어 종속성이 있는 작업을 재정렬하면 실행 결과가 변경되지 않습니다(이것이 바로 직렬 방식의 의미론이 제어 종속성이 있는 작업 재정렬을 허용하는 이유입니다). 제어 종속성이 있는 작업의 순서를 바꾸면 프로그램의 실행 결과가 변경될 수 있습니다. 위 내용은 Java 메모리 모델에 대한 심층 분석입니다. 내용 재정렬에 대한 자세한 내용은 PHP 중국어 웹사이트(www.php.cn)를 참고하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.