>Java >java지도 시간 >Java 가시성 메커니즘의 원리

Java 가시성 메커니즘의 원리

高洛峰
高洛峰원래의
2016-11-14 09:26:13988검색

기본 개념

1. 가시성

한 스레드가 공유 변수를 수정하면 다른 스레드가 수정된 값을 읽을 수 있습니다.

2. 메모리 장벽

프로세서가 메모리 작업에 대한 순차적 제한을 구현하는 명령 집합입니다.

3. 버퍼 라인

CPU는 캐시에 할당할 수 있는 가장 작은 저장 단위를 알려줍니다. 프로세서가 캐시 라인을 채우면 전체 캐시 라인이 로드됩니다.

4. 접두사가 붙은 명령어 잠금

접두사가 붙은 명령어 잠금은 멀티 코어 프로세서에서 두 가지 작업을 수행합니다.

1) 현재 프로세서 연결의 캐시 라인 데이터를 변경합니다. 시스템 메모리에.

2) 메모리에 다시 쓰는 이 작업은 메모리 주소에서 다른 CPU에 의해 캐시된 데이터를 무효화합니다.

5. 캐시 일관성 프로토콜

0은 각 프로세서의 캐시가 일관성을 보장하며 각 프로세서는 캐시된 데이터가 있는지 확인합니다. 값이 만료되었습니다. 프로세서가 캐시 라인에 해당하는 주소가 수정되었음을 발견하면 현재 프로세서의 캐시 라인을 잘못된 상태로 설정합니다. 프로세서가 이 데이터를 읽거나 쓸 때 메모리의 데이터를 프로세서 캐시로 다시 읽습니다.

6.CAS

CompareAndSwap 비교 및 ​​교체

CAS 작업에는 이전 값(CAS 작업을 수행하기 전의 값, 예상 값)과 새 값, 현재 값이 이전 값과 같을 때만 현재 값을 새 값으로 설정할 수 있으며, 그렇지 않으면 설정되지 않습니다. 이는 하드웨어에 의해 보장되는 원자적 작업입니다.

7. 재정렬 규칙

기본적으로 JMM에는 프로그램 실행 결과가 변경되지 않는 한 컴파일러와 프로세서에 대한 재정렬 제한이 하나만 있습니다(단일 스레드 또는 올바르게 동기화된 다중 참조). -스레드 환경), 그러면 컴파일러와 프로세서가 최적화될 수 있습니다.

휘발성

위의 Lock 접두어 명령어와 캐시 일관성 프로토콜에서 볼 수 있듯이 이것이 휘발성의 구현 원칙입니다.

사실 Valatile 변수를 작성할 때 실제로 가시성 목적을 달성하기 위해 Lock 접두사가 추가됩니다.

final

최종 필드는 명시적으로 한 번만 할당할 수 있지만 이것이 최종 필드를 여러 번 초기화할 수 없다는 의미는 아닙니다.

예: final int i; 생성자에 i가 할당되기 전에 기본값인 0으로 초기화됩니다. 이는 코드를 디버깅하여 증명할 수 있습니다.

최종 필드의 값이 초기화 전에 액세스되지 않도록 하기 위해 프로그래머는 한 가지만 확인하면 됩니다. 즉, 생성자에서 생성되는 객체(this)가 "Escape"를 수행하면 동기화 수단 없이 기본 유형 및 참조 유형을 포함하여 모든 스레드에서 볼 수 있는 최종 필드가 생성자를 통해 올바르게 초기화되었는지 확인할 수 있습니다.

생성되는 개체의 예는 이스케이프입니다.

public class FinalTest{ 
   final int i; 
   static FinalTest obj; 
 
   public FinalTest(){ 
   i  =1; 
   /** 
   *这里会使正在被构造的对象逸出,如果和上一句做了重排序,那么其他线程就可以通过obj访问到还为被初始化的final域。 
   **/ 
   obj = this;  
  } 
}

Happens-Before 규칙

발생 전의 의미

Happen -Before 규칙 두 작업 간의 순차적 관계를 설명하는 데 사용됩니다. 이 두 작업은 하나의 스레드에 있을 수도 있고 그렇지 않을 수도 있습니다. 이 순서는 엄밀히 말하면 실행 시간 순서를 의미하는 것이 아니라 이전 작업의 결과가 후속 작업에 표시된다는 의미입니다.

Happens-Before 관계는 다음과 같이 정의됩니다.

다른 작업보다 먼저 발생하면 첫 번째 작업의 실행 결과가 두 번째 작업에 표시되고 첫 번째 작업의 실행 순서가 두 번째 작업 이전입니다

두 작업 사이에 사전 발생 관계가 존재한다고 해서 Java 플랫폼의 특정 구현이 사전 발생 관계에 지정된 순서대로 실행되어야 한다는 의미는 아닙니다. 재정렬 후의 실행 결과가 이전 발생 관계에 따른 실행 결과와 일치하면 이러한 재정렬은 불법이 아닙니다.

예를 들어 프로그램 실행 순서에서 A가 B보다 앞서고 A가 공유 변수를 수정하고 B가 우연히 공유 변수를 사용하는 경우 A가 B보다 먼저 발생해야 합니다. 더 간단하게 말하면, 이는 A의 공유 변수 수정이 B가 이를 실행할 때 B에 표시되어야 함을 의미합니다.

선행 규칙

프로그램 순서 규칙: 스레드의 각 작업은 해당 스레드의 후속 작업보다 먼저 발생합니다.

모니터 잠금 규칙: 잠금 해제는 이후 잠금이 잠기기 전에 발생합니다.

휘발성 규칙: 휘발성 필드에 대한 쓰기는 이 휘발성 필드에 대한 후속 읽기 전에 발생합니다.

전이성: B보다 먼저 발생하고 B가 C보다 먼저 발생하면 A가 C보다 먼저 발생합니다.

start() 규칙: 스레드 A가 ThreadB.start() 작업을 수행하면 스레드 B의 작업보다 먼저 스레드 A의 ThreadB.start() 작업이 발생합니다.

join() 규칙: 스레드 A가 ThreadB.join() 작업을 실행하고 성공적으로 반환하면 스레드 B의 모든 작업은 스레드 A가 ThreadB.join() 작업에서 성공적으로 반환되기 전에 발생합니다.

이 모든 규칙에 대한 설명: Ahappens-before B는 A가 B보다 먼저 발생해야 한다는 의미는 아니지만, A가 B보다 먼저 발생했다면 A의 연산 결과는 B에게 표시되어야 함을 의미합니다.


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