volatile,final 메모리 의미 및 happen-before 규칙

6422 단어 자바
volatile 과 final 은 스 레 드 를 동기 화 할 때 큰 역할 을 합 니 다.그러면 자바 메모리 에서 이 두 키 워드 는 어떻게 스 레 드 와 동기 화 되 었 습 니까?그리고 스 레 드 의 happen-before 규칙 은 어떻게 정의 되 었 습 니까?
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 후속 으로 이 잠 금 의 잠 금 추가 에 대해 서도 잘 이해 할 수 있 습 니 다
  • volatile 규칙,즉 우리 가 하나의 변 수 를 volatile 로 정의 할 때 서로 다른 스 레 드 에서 이 변 수 를 읽 고 쓰 는 작업 을 하 더 라 도 JMM 은 읽 기 작업 의 결 과 를 쓰기 작업 에 볼 수 있 도록 보장 할 수 있다
  • 또한 스 레 드 의 start(),join()에 대해 우 리 는 스 레 드 의 시작,join()에 어떠한 자 물 쇠 를 추가 하지 않 았 더 라 도 JMM 은 스 레 드 의 시작 이 스 레 드 내부 작업 보다 먼저 실 행 될 것 을 보장 합 니 다.스 레 드 의 내부 작업 은 다음 스 레 드 의 join()보다 먼저 실 행 됩 니 다

  • 요약 하면 happen-before 는 JMM 이 프로그래머 에 대한 보증 이자 컴 파일 러 와 프로세서 에 대한 재 정렬 시의 제약 이다.

    좋은 웹페이지 즐겨찾기