읽기 및 쓰기 마지막 필드는 더 일반 변수 액세스 같다
최종 규칙 재정렬 도메인
최종 도메인의 경우, 컴파일러와 프로세서는 두 개의 재주문 규칙을 준수합니다.
(1) 최종 필드의 생성자에 기록하고 참조하는 오브젝트가 참조 변수에 할당 된이 구성은, 재정렬이 두 작업 사이 아니다.
(2) 최종적인 기준을 포함하는 제 1 목표 영역을 판독 한 후 최종 초기 필드 판독은, 재정렬이 두 작업 사이 아니다.
예
public class FinalExample {
int i;普通变量
final int j;final变量
static FinalExample obj;
public FinalExample() { 构造函数
i = 1; 写普通域
j = 2; 写final域
}
public static void writer() { 写线程A执行
obj = new FinalExample();
}
public static void reader() { 读线程B执行
FinalExample object = obj; 读对象引用
int a = object.i; 读普通域
int b = object.j; 读final域
}
}
기록기 스레드 A가 실행을 가정한다 (다른 스레드 B 하였다)에있어서, 판독기 () 메소드를 실행.
쓰기 재정렬 최종 도메인 규칙
글 마지막 필드 재정렬 규칙은 생성자 외부의 마지막 필드를 재정렬 쓰기를 금지합니다.
(1)은 재정렬 JMM 최종 필드를 외부 생성자 물품 컴파일러 방지한다.
(2) 컴파일러가 최종 필드 후 작성합니다하기 전에 StoreStore 장벽 삽입 생성자 반환. 이 장벽은 생성자 외부의 마지막 필드를 재정렬 쓸 수있는 프로세서를 금지합니다.
라이터 () 메소드
(1) 타입 FinalExample의 객체를 생성한다.
(2) 오브젝트 참조 변수 OBJ 참조하여 할당.
수 있도록 규칙을 재정렬 글 마지막 필드 :
볼, 최종 도메인 객체 전에 스레드에 대한 참조를 올바르게 개체 위에 초기화되었습니다.
이 도메인은 통상의 보안 쓰레드 B 오브젝트 레퍼런스 OBJ 아마도 아직 생성되지 않은 오브젝트 OBJ (나는 정규 도메인 물품 외부 생성자, 또한 초기 값을 재 배열 할 때 "볼"이없는 공통 도메인 내가 작성하지)
최종 규정 재정렬 도메인 읽기
스레드에서 판독 필드 최종 규정 재정렬, 제 1 판독 영역의 기준 시온 최종 판독하고 객체는 두 동작들을 재정렬 JMM 금지 프로세서를 포함한다. LoadLoad 컴파일러는 최종 읽기 도메인 작업의 앞에 장벽을 삽입합니다.
판독 우선 초기 판독 최종 개체 참조 필드는 객체의 두 동작 간의 간접 종속성을 포함한다. 컴파일러 준수 간접 의존성 때문에, 컴파일러는이 두 작업의 재정렬을 수행합니다.
Reder () 메소드는 세 개의 동작이 포함
(1)의 초기의 판독 기준 변수 OBJ
객체 일반 도메인 J 가리키는 obj를 (2) 초기의 판독 기준 변수
i가 가리키는 오브젝트 최종 필드 obj를. (3) 제 1 판독 기준 변수
라이터 스레드 A가 발생하지 않은 것으로 간주 됨 모든 재정렬하고, 프로그램 실행이 프로세서에 간접적으로 의존 따르지 않는
일반적인 도메인 오브젝트를 판독하기위한 동작은 오브젝트 레퍼런스를 판독하도록 프로세서 전에 재 배열된다. 독서이 잘못 읽기 작업이며, 도메인이 스레드 A가 기록 된 기록되지 않은 일반적인 도메인입니다. 최종 판독 동작 필드 규칙 마지막 스레드 A 도메인을 초기화 된 시간에 객체 참조를 판독 한 후 "정의"재정렬 최종 타겟 영역을 읽을 것이고, 이는 적절한 판독 동작 동안
최종 필드를 읽어 재정렬 규칙은 확인 : 대상 도메인의 마지막 읽기 전에, 우리는 먼저 최종 필드에 개체 참조가 포함 읽습니다. 참조가 null가 아닌 경우,이 예에서, 다음 객체 참조 최종 도메인 이전 스레드를 초기화해야합니다.
최종 필드는 참조 형
public class FinalReferenceExample {
final int[] intArray; final是引用类型
static FinalReferenceExample obj;
public FinalReferenceExample() { 构造函数
intArray = new int[1]; 1
intArray[0] = 1; 2
}
public static void writerOne() { 写线程A执行
obj = new FinalReferenceExample(); 3
}
public static void writerTwo() { 写线程B执行
obj.intArray[0] = 2; 4
}
public static void reader() { 读线程C执行
if (obj != null) { 5
int temp1 = obj.intArray[0]; 6
}
}
}
기준 유형의 기록 필드 최종 재정렬 컴파일러 규칙 프로세서는 다음의 제약 조건을 추가
하여 최종 기준 객체의 생성자 도메인의 부재를 작성하고,이 후, 객체의 생성자 외부 구성된 변수에 할당 기준에 대한 참조는, 두 간격이 재정렬 동작 할
리더 스레드 JMM을 보장하지만 볼 수 이상의 기입 C에서 마지막으로 도메인 객체 기준 부재에 기록 생성자 스레드.
어레이의 적어도 1로 표시되는, 즉 0에서 C 표시한다. 작가 스레드 B는 볼 수없는, 쓰기 배열 요소, 읽기 스레드 C가 표시 될 수 있습니다.
JMM은 데이터 읽기 및 쓰기 스레드 B 스레드 C는이 시간에 결과를 예측할 수 사이에 경쟁이 있기 때문에 볼 쓰기 스레드 B 스레드 C를 읽을 보장 할 수 없습니다.
당신이 읽기 쓰기 스레드 B 스레드가 쓰기, 쓰기에 배열 요소를 참조 C 있는지 확인하려면, 메모리 스레드 가시성을 읽을 수 있도록 스레드 B와 C 사이의 동기화 프리미티브 (잠금 또는 휘발성)의 사용을 필요로한다.
당신은 최종 참조 생성자에서 벗어날 수 없다
어떤 스레드가 최종 개체 변수 도메인의 기준점으로 참조 변수에서 볼 수 있습니다 전에 제대로 생성자에서 초기화되었습니다 서면 최종 필드 재정렬 규칙이 있음을 확인합니다. 이 효과를 얻으려면, 당신은 또한 보증이 필요합니다 내부 생성자, 더 이상 객체 참조 생성자 탈출입니다 볼 수있는 다른 스레드에 대해이 구조화 된 객체 참조를 만들기 위해 뛰었다.
public class FinalReferenceEscapeExample {
final int i;
static FinalReferenceEscapeExample obj;
public FinalReferenceEscapeExample() {
i = 1; 1写final域
obj = this; 2 this引用在此"逸出"
}
public static void writer() {
new FinalReferenceEscapeExample();
}
public static void reader() {
if (obj != null) { 3
int temp = obj.i; 4
}
}
}
() 메소드 wirter 스레드 A가 실행하는 가정을, 다른 스레드 B 리더 () 메소드를 실행. 2 동작 객체 여기 스레드 B 전에 가시광으로 구성되도록 완성되지 않았다. 2 여기에 작업이 생성자의 마지막 단계, 및 운영 1의 방법 뒤에 2 행의 작업 스레드 경우에도, 당신은 프로그램의 마지막 필드의 구덩이 여전히 초기화 값을 볼 수 없습니다) (읽기 실시합니다 여기 한 동작 때문에 작업은 2 사이에 다시 정렬 할 수있다
참조 된 개체가 도메인가 초기화되지 않았기 때문에, 최종 구성된 다른 스레드를 위해 보이지 않는 생성자를 반환하기 전에. 생성자가 반환 된 후, 임의의 스레드에 최종 필드가 제대로 초기화 후 가치를 보장합니다.
JSR-133 의미 최종 향상된
기존의 자바 메모리 모델에서 가장 심각한 결함 중 하나는 스레드가 마지막 필드의 값이 변경됩니다 볼 수 있습니다.
(스레드는 현재 최종 필드 (기본 값은 전에 초기화되지 않은)를 0으로 설정 정수를 볼 때 예를 들어, 갈 시간이 지나면이 분야의 스레드 최종 값을 읽을 수 있지만 값을 1로 발견 초기화 후에 스레드 값).
가장 일반적인 예는 기존의 자바 메모리 모델, 문자열의 값이 변경 될 수 있습니다.
이러한 취약점을 해결하기 위해, JSR-133 전문가 그룹은 최종 시맨틱을 향상시킨다.
최종 읽기 - 쓰기 및 재 주문 규칙에 대한 필드를 증가하여, 초기화는 자바 프로그래머에 대한 보안을 제공 할 수 있습니다 개체만큼 긴 제대로 구성되어 (생성자 건설 개체에는 "탈출"을 인용 없음), 동기식 사용할 필요가 없습니다 값 (잠금 휘발성의 사용을 의미한다) 모든 스레드가 마지막 필드 후 생성자 초기화 볼 수 있도록 할