happens-before 와 as-if-serial 의 미 를 깊이 이해 하 다.

개술
본 고 는 대부분 을 정리 하고 온고지신 하 며 기초 에 대한 이 해 를 깊이 있 게 한다.
명령 시퀀스 의 정렬
우 리 는 코드 를 작성 할 때 보통 위 에서 아래로 작성 합 니 다.실행 하고 자 하 는 순 서 는 이론 적 으로 도 점차적으로 직렬 로 실행 되 지만 성능 을 향상 시 키 기 위해 컴 파일 러 와 처리 기 는 명령 을 다시 정렬 합 니 다.
1)컴 파 일 러 최적화 정렬.컴 파일 러 는 단일 스 레 드 프로그램의 의 미 를 바 꾸 지 않 는 전제 에서 문장의 실행 순 서 를 다시 배정 할 수 있다.
2)지령 급 병렬 정렬.현대 프로 세 서 는 명령 급 병렬 기술 을 채택 하여 여러 명령 을 중첩 하여 집행 한다.만약 데이터 의존성 이 존재 하지 않 는 다 면,프로 세 서 는 문장 이 기계 명령 에 대응 하 는 실행 순 서 를 바 꿀 수 있다.
3)메모리 시스템 의 재 정렬.프로세서 가 캐 시 와 읽 기/쓰기 버퍼 를 사용 하기 때문에 로드 와 저장 작업 이 무질서 하 게 실 행 될 수 있 습 니 다.
자바 소스 코드 부터 최종 실제 실 행 된 명령 시퀀스 까지 다음 세 가지 재 정렬 을 거 칩 니 다.

happens-before 의미
JDK 5 부터 자바 는 새로운 메모리 모델 을 사용 하고 happens-before 의 개념 으로 작업 간 의 메모리 가시 성 을 논술 한다.그럼 도대체 happens-before 가 뭐 예요?
JMM 에서 만약 에 한 조작 이 실 행 된 결과 가 다른 조작 에 대해 보 여야 한다 면 이 두 조작 사이 에 happens-before 관계 가 존재 해 야 한다.여기 서 언급 한 두 조작 은 한 스 레 드 안에 있 을 수도 있 고 서로 다른 스 레 드 사이 에 있 을 수도 있다.
happens-before 규칙 은 다음 과 같 습 니 다.
프로그램 순서 규칙:단일 스 레 드 의 모든 작업 에 대해 서 는 happens-before 가 이 스 레 드 에서 임의의 후속 작업 을 수행 합 니 다.
모니터 잠 금 규칙:자물쇠 에 대한 잠 금 해제,happens-before 는 그 다음 에 이 자물쇠 에 자 물 쇠 를 추가 합 니 다.
volatile 변수 규칙:volatil e 역 에 대한 쓰기,happens-before 는 임의의 후속 으로 이 volatil e 역 에 대한 읽 기.
전달 성:A happens-before B,그리고 B happens-before C 가 있다 면 A happens-before C.
주의:
두 작업 사이 에 happens-before 관 계 를 가 진 다 는 것 은 앞의 작업 이 반드시 다음 작업 전에 실행 되 어야 한 다 는 것 을 의미 하지 않 습 니 다.happens-before 는 앞의 작업(실 행 된 결과)에 대해 다음 작업 을 볼 수 있 고 앞의 작업 은 순서대로 두 번 째 작업 전에 배열 해 야 합 니 다.
happens-before 와 JMM 의 관 계 는 그림 과 같다.

그림 에서 보 듯 이 하나의 happens-before 규칙 은 하나 이상 의 컴 파일 러 와 프로세서 의 정렬 규칙 에 대응 합 니 다.
다시 정렬
재 정렬 이란 컴 파일 러 와 프로세서 가 프로그램의 성능 을 최적화 하기 위해 명령 서열 을 재 정렬 하 는 수단 을 말한다.
만약 에 두 작업 이 같은 변수 에 접근 하고 이 두 작업 중 하 나 는 쓰기 작업 이 라면 이 두 작업 사이 에 데이터 의존 도가 존재 합 니 다.데이터 의존 도 는 다음 세 가지 유형 으로 나 뉜 다.

위의 상황 은 두 작업 의 실행 순 서 를 다시 정렬 하면 프로그램의 실행 결과 가 달라 진다.컴 파 일 러 와 프로 세 서 는 작업 에 대해 정렬 을 다시 할 수 있 지만 컴 파 일 러 와 프로 세 서 는 정렬 을 다시 할 때 데이터 의존성 을 준수 하고 컴 파 일 러 와 프로 세 서 는 데이터 의존 관계 가 존재 하 는 두 작업 의 실행 순 서 를 바 꾸 지 않 습 니 다.
주의:
여기 서 말 하 는 데이터 의존 도 는 단일 프로세서 에서 실행 되 는 명령 시퀀스 와 단일 스 레 드 에서 만 실 행 됩 니 다.서로 다른 프로세서 와 서로 다른 스 레 드 간 의 데이터 의존 도 는 컴 파일 러 와 프로세서 에 의 해 고려 되 지 않 습 니 다.
as-if-serial 의미
as-if-serial 의 미 는 아무리 정렬 을 다시 하 더 라 도 단일 스 레 드 프로그램의 실행 결 과 는 바 꿀 수 없다 는 것 이다.컴 파일 러,runtime,프로세서 모두 as-if-serial 의 미 를 지 켜 야 합 니 다.따라서 컴 파일 러 와 프로 세 서 는 데이터 의존 관계 가 존재 하 는 작업 에 대해 정렬 을 다시 하지 않 습 니 다.이러한 정렬 은 실행 결 과 를 바 꿀 수 있 기 때 문 입 니 다.그러나 작업 간 에 데이터 의존 관계 가 존재 하지 않 으 면 컴 파일 러 와 프로세서 에 의 해 정렬 될 수 있 습 니 다.
다음은 책의 실례(원 의 면적 계산)로 설명 한다.

double pi = 3.14;  
// Adouble r = 1.0;  
// Bdouble area = pi * r * r; // C
위의 세 작업 의 데이터 의존 관 계 는 그림 과 같다.

A 와 C 사이 에는 데이터 의존 관계 가 존재 하 는 동시에 B 와 C 사이 에 도 데이터 의존 관계 가 존재 한다.따라서 최종 적 으로 실 행 된 명령 시퀀스 에서 C 는 A 와 B 의 앞 에 다시 정렬 되 어 서 는 안 된다(C 가 A 와 B 의 앞 에 배열 되 어 있 기 때문에 프로그램의 결과 가 바 뀔 것 이다).그러나 A 와 B 사이 에는 데이터 의존 관계 가 없고 컴 파 일 러 와 프로 세 서 는 A 와 B 사이 의 실행 순 서 를 다시 정렬 할 수 있다.
이 프로그램의 실행 가능 한 두 가지 순서:

as-if-serial 의 미 는 단일 스 레 드 프로그램 을 보호 합 니 다.as-if-serial 의 미 를 지 키 는 컴 파일 러,runtime 과 프로세서 가 공동으로 단일 스 레 드 프로그램 을 작성 하 는 프로그래머 에 게 환각 을 만 들 었 습 니 다.단일 스 레 드 프로그램 은 프로그램의 순서에 따라 실 행 됩 니 다.
프로그램 순서 규칙
happens-before 의 프로그램 순서 규칙 에 따라 원 의 면적 을 계산 하 는 예제 코드 는 3 개의 happens-before 관계 가 존재 합 니 다.
1) A happens-before B。
2) B happens-before C。
3) A happens-before C。
이곳 의 세 번 째 happens-before 관 계 는 happens-before 의 전달 성에 따라 추론 된다.
주의:
여기 서 A happens-before B 는 실제 집행 할 때 B 는 A 보다 먼저 집행 할 수 있 고 JMM 은 A 에 게 반드시 B 전에 집행 하 라 고 요구 하지 않 는 다.JMM 은 이전 작업(실 행 된 결과)에 만 다음 작업 을 볼 수 있 도록 요구 하고 이전 작업 은 두 번 째 작업 전에 순서대로 배열 합 니 다.여기 서 A 를 조작 한 실행 결 과 는 조작 B 를 볼 필요 가 없 으 며,다시 정렬 하여 A 와 조작 B 를 조작 한 후의 실행 결 과 는 조작 A 와 조작 B 가 happens-before 순서에 따라 실 행 된 결과 와 일치 합 니 다.이런 상황 에서 JMM 은 이러한 정렬 이 불법 이 아니 라 고 생각 하고 JMM 은 이러한 정렬 을 허용 한다.
정렬 이 다 중 스 레 드 에 미 치 는 영향
정렬 을 다시 하면 다 중 스 레 드 프로그램의 실행 결 과 를 바 꿀 수 있 습 니까?아니면 책 속 의 예 를 빌려 씁 니까?

class ReorderExample {
 int a = 0;
 boolean flag = false;
 public void writer() {
  a = 1;   // 1
  flag = true;  // 2
 }
 public void reader() {
  if (flag) {  // 3
  int i = a * a; // 4
  }
 }
}
flag 변 수 는 변수 a 가 기록 되 었 는 지 여 부 를 표시 하 는 태그 입 니 다.여기 서 두 개의 스 레 드 A 와 B 가 있다 고 가정 하고 A 는 먼저 writer()방법 을 집행 한 다음 에 B 스 레 드 는 이어서 reader()방법 을 집행 한다.스 레 드 B 가 작업 4 를 실행 할 때 스 레 드 A 가 공유 변수 a 에 대한 기록 을 볼 수 있 습 니까?
정 답 은 반드시 볼 수 있 는 것 은 아니다.
조작 1 과 조작 2 는 데이터 의존 관계 가 없 기 때문에 컴 파일 러 와 처리 장 치 는 이 두 조작 을 다시 정렬 할 수 있 습 니 다.마찬가지 로 조작 3 과 조작 4 는 데이터 의존 관계 가 없고 컴 파일 러 와 프로세서 도 이 두 조작 에 대해 다시 정렬 할 수 있다.
1 과 2 를 다시 정렬 할 때 어떤 효과 가 있 습 니까?(가상 화살 선 표지 의 잘못된 읽 기 동작,실제 화살 선 표지 로 정확 한 읽 기 동작 을 표시 합 니 다.)

그림 에서 보 듯 이 조작 1 과 조작 2 는 정렬 을 다시 했다.프로그램 이 실 행 될 때 스 레 드 A 는 먼저 태그 변수 flag 를 쓰 고 그 다음 에 스 레 드 B 는 이 변 수 를 읽 습 니 다.조건 이 진짜 로 판단 되 기 때문에 스 레 드 B 는 변 수 를 읽 습 니 다.이때 변수 a 는 스 레 드 A 에 기록 되 지 않 았 습 니 다.여기 서 다 중 스 레 드 프로그램의 의미 가 정렬 되 어 파괴 되 었 습 니 다!
3 과 4 중 정렬 을 조작 할 때 어떤 효과 가 있 습 니까?다음은 조작 3 과 조작 4 를 정렬 한 후 프로그램 이 실행 하 는 순서 그림 입 니 다.

프로그램 에서 조작 3 과 조작 4 는 제어 의존 관계 가 존재 한다.코드 에 제어 의존성 이 존재 할 때 명령 시퀀스 실행 의 병행 도 에 영향 을 줄 수 있 습 니 다.이 를 위해 컴 파일 러 와 프로 세 서 는 관련 성 이 병행 도 에 미 치 는 영향 을 극복 하기 위해 추측 집행 을 한다.프로세서 의 추측 실행 을 예 로 들 면,라인 B 를 실행 하 는 프로 세 서 는 a*a 를 미리 읽 고 계산 한 다음,계산 결 과 를 정렬 버퍼 라 는 하드웨어 캐 시 에 임시로 저장 할 수 있다.조작 3 의 조건 이 사실 로 판단 되면 이 계산 결 과 를 변수 i 에 기록 합 니 다.실질 적 으로 조작 3 과 4 에 대해 재 정렬 을 했 을 것 이 라 고 추측 합 니 다.여기 서 재 정렬 은 다 중 스 레 드 프로그램의 의 미 를 파괴 합 니 다!
주의:
단일 스 레 드 프로그램 에 서 는 제어 의존 이 있 는 작업 에 대해 정렬 을 다시 하고 실행 결 과 를 바 꾸 지 않 습 니 다.
다 중 스 레 드 프로그램 에서 제어 의존 이 있 는 작업 에 대한 정렬 을 다시 하면 프로그램의 실행 결 과 를 바 꿀 수 있 습 니 다.
레 퍼 런 스
《자바 병발 프로 그래 밍 의 예술》.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기