volatile,final 메모리 의미 및 happen-before 규칙
6422 단어 자바
volatile 의 메모리 의미
volatile 은 변 수 를 수식 하 는 데 사 용 됩 니 다.변 수 는 매번 메 인 메모리 에서 읽 을 수 있 지만 원자 성 을 보장 하지 않 습 니 다.먼저 구체 적 인 예 를 보 겠 습 니 다.
public class VolatileExample {
private static volatile long v1 = 10L;
public static void setV1(long l){
v1 = l;
}
public static long getV1(){
return v1;
}
public static void getAndIncrement() {
v1++;
}
public static void main(String[] args){
for (int i = 0;i < 1000;i++){
new Thread(new Runnable() {
@Override
public void run() {
getAndIncrement();
}
}).start();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("result: "+v1);
}
}
위 getAndIncrement()는 아래 와 같 습 니 다.
/**
* , V1 , V1 +1 , V1 , 1 ,
* 2 V1 , V1 +1 , , 1
* V1 , volatile
* , , 。
* */
public static void getAndIncrement() {
v1++;
}
volatile 정렬 금지 규칙
아래 의 예 를 보 세 요.
class VolatileExample{
int a = 0;
volatile boolean flag = false; //volatile
public void writer(){
a = 1; // 1
flag = true; // 2
}
public void reader(){
if(flag){ // 3
int i = a; // 4
...
}
문제 가 있 습 니 다.만약 에 flag 가 volatile 에 의 해 수식 되 지 않 았 다 면 위의 문 구 는 1,2,3,4 에 정렬 할 가능성 이 존재 합 니 다.그러면 스 레 드 1 이 writer()함 수 를 실행 하고 스 레 드 2 가 reader()를 실행 한다 고 가정 합 니 다.스 레 드 1 이 먼저 문 구 를 2 실 행 했 을 때 스 레 드 2 실행 문 구 는 3 이 고 flag 가 true 인 것 을 발견 하면 실행 문 구 는 4 입 니 다.이때 스 레 드 1 은 실행 문 구 를 1 하지 않 았그러면 문장 4 에서 얻 은 a 값 은 1 이 아니다.가상 컴퓨터 의 재 정렬 은 같은 스 레 드 안의 문 구 를 재 정렬 하 는 데 영향 을 받 지 않도록 하 는 것 일 뿐 스 레 드 간 의 실행 순 서 는 보장 되 지 않 습 니 다.만약 에 flag 에 volatile 수식 을 사용 하면 상기 문 제 를 피 할 수 있 습 니 다.volatile 은 재 정렬 에 다음 과 같은 규칙 이 있 습 니 다.
volatile 정렬 규칙:1.두 번 째 작업 이 volatile 쓰기 작업 일 때 첫 번 째 작업 이 무엇 이 든 정렬 을 금지 하기 때문에 문장 1 과 2 는 정렬 을 다시 할 수 없습니다.2.첫 번 째 작업 이 volatile 읽 기 작업 일 때 두 번 째 작업 이 무엇 이 든 정렬 을 다시 하지 마 십시오.이 문장 3 과 4 는 정렬 을 다시 할 수 없습니다.첫 번 째 작업 이 volatile 쓰기 일 때두 번 째 동작 은 volatile 읽 을 때 정렬 을 다시 하 는 것 을 금지 합 니 다.
따라서 volatile 수식 이 있 습 니 다.상기 문 구 는 1 과 2 를 다시 정렬 할 수 없고 문 구 는 3 과 4 를 다시 정렬 하지 않 습 니 다.그러면 두 스 레 드 에서 상기 reader()와 writer()를 실행 하면 상기 문제 가 발생 하지 않 습 니 다.
final 필드 의 정렬 규칙 쓰기
final 정렬 규칙 에 대해 다음 과 같은 제한 이 있 습 니 다.final 도 메 인의 쓰기 정렬 은 구조 함수 외 에 정렬 할 수 없습니다.즉,인 스 턴 스 대상 이 임의의 스 레 드 에 보이 기 전에 final 도 메 인 은 초기 화 되 었 을 것 입 니 다.그러나 일반 도 메 인 이 이 보증 을 가지 지 않 으 면 자바 메모리 모델 은 구조 함수 가 돌아 오기 전에 StoreStore 장벽 을 추가 합 니 다.즉,:
final ;
StoreStore ;
return
다음 코드 를 보십시오.
public class FinalExample{
static FinalExample obj;
int i; //
final int j ; //final
public FinalExample(){
i = 10; // i
j = 20; // j 20
}
public void writer(){
/**
* , j return , i
*
* */
obj = new FinalExample();
}
public void reader(){
FinalExample object = obj;
/**
* B reader , , obj , i = 10
* , i 。
* */
int a = obj.i;
/**
* final StoreStore, final
* , j 。
* */
int b = obj.j;
}
final 필드 의 정렬 규칙 읽 기
한 스 레 드 에서 첫 번 째 읽 기 대상 은 첫 번 째 읽 기 대상 에 포 함 된 final 도 메 인 을 참조 합 니 다.자바 메모리 모델 은 이 두 작업 의 정렬 을 금지 합 니 다.컴 파일 러 는 final 도 메 인 을 읽 기 전에 Load 장벽 을 삽입 합 니 다.즉,:
;
LoadLoad ;
final ;
fianl 도 메 인 은 구조 함수 에서 넘 칠 수 없습니다.
예 는 다음 과 같다.
public class FinalExample {
private final int i;
private static FinalExample obj;
public FinalExample(){
i = 2; // 1
obj = this; // 2, ,
}
public static void writer(){
new FinalExample(); // A writer()
}
public static void reader(){
if(obj != null){ // B reader(), 2 , obj , i , final 。
int temp = obj.i;
}
}
}
happen-before 규칙
정의.
happen-before 는 두 작업 간 의 실행 순 서 를 지정 합 니 다.이 두 작업 은 하나의 스 레 드 안에 있 을 수도 있 고 서로 다른 스 레 드 사이 에 있 을 수도 있 습 니 다.JMM(Java 메모리 모델)은 happen-before 규칙 을 통 해 프로그램 원숭이 에 게 스 레 드 를 뛰 어 넘 는 메모리 가시 성 을 제공 합 니 다.즉,스 레 드 A 의 쓰기 동작 a happen-before 가 스 레 드 B 의 읽 기 동작 에 있 으 면 a 작업 과 b 작업 이 서로 다른 스 레 드 에서 실 행 됩 니 다.그러나 JMM 은 프로그램 원숭이 에 게 a 의 결 과 를 b 조작 에 볼 수 있 도록 보증한다.
happen-before 규칙 정의
1.프로그램 순서 실행 규칙:한 스 레 드 의 임 의 작업,happen-before 는 이 스 레 드 의 임 의 후속 작업
2.모니터 잠 금 규칙:잠 금 해제,happen-before 는 이 잠 금 에 대한 추가 잠 금 을 추가 합 니 다.
3.volatile 규칙:volatile 변수 에 대한 쓰기 동작,happen-before 는 이 volatile 에 대한 읽 기 동작 을 후속 으로 합 니 다.
4.전달 성:A happen-before 가 B,B happen-before C 라면 A happen-before C
5.start()규칙 스 레 드 A 가 ThreadB.start()시작 스 레 드 B 를 실행 하면 A 의 ThreadB.start()는 happen-before 가 스 레 드 B 에서 임의로 작 동 합 니 다.
6.join()규칙 은 스 레 드 A 가 ThreadB.join()을 실행 하고 성공 적 으로 돌아 오 면 스 레 드 B 의 임 의 조작 happen-before 는 스 레 드 A 의 ThreadB.join()에 있 습 니 다.
총결산
4.567917.프로그램 원숭이 는 코드 를 작성 할 때 모두 순서대로 작성 합 니 다.먼저 1 을 조작 하고 2 를 조작 하면 조작 1 이 조작 2 보다 먼저 실 행 될 것 이 라 고 기대 할 수 있 습 니 다.그러나 실제로 JVM 은 조작 1 이 반드시 조작 2 보다 먼저 실 행 될 것 이 라 고 보장 하 지 는 않 습 니 다.그러나 이것 은 조작 1 의 결과 가 조작 2 의 결 과 를 볼 수 있 고 언제 정렬 을 다시 할 것 입 니까?1 과 2 가 데이터 가 없 을 때 이것 은 첫 번 째 happen-before 규칙 입 니 다.또한 쉽게 이해 할 수 있 습 니 다.happen-before 는 전달 성 을 가지 고 있 습 니 다
4.567917.다른 규칙,예 를 들 어 모니터 잠 금 규칙,하나의 잠 금 해제,happen-before 후속 으로 이 잠 금 의 잠 금 추가 에 대해 서도 잘 이해 할 수 있 습 니 다
요약 하면 happen-before 는 JMM 이 프로그래머 에 대한 보증 이자 컴 파일 러 와 프로세서 에 대한 재 정렬 시의 제약 이다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Is Eclipse IDE dying?In 2014 the Eclipse IDE is the leading development environment for Java with a market share of approximately 65%. but ac...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.