동기화 된 이후 "보편적"이며, 왜 우리는 휘발성이 필요합니까?

하나님의 경로에 자바 엔지니어의 GitHub의 6.6k 스타, 그것에 대해 알게하지?

하나님의 경로에 자바 엔지니어의 GitHub의 6.6k 스타는 정말 보지 않는다?

하나님 자바 엔지니어의 도로 GitHub의 6.6k 스타, 정말 그것에 대해 알지 아니하기로 작정?

내 블로그 공공의 수에서 동시 프로그래밍에 대한 기사를 많이 게시, 이전 기사, 우리는 도입보다 두 키워드 자바 동시성의 중요한 두 : 동기화 및 휘발성

우리는 간단히 관련 내용을 검토 :

1, 위해 자바 프로그래밍 언어는 원자, 가시성 및 순서 문제의 존재에 의해 복잡 및 동기화, 휘발성, 최종 concurren 가방 등의 동시 처리 관련 키워드의 범위를 제공 해결합니다. ( 그리고 누군가가 그에게 발행 된 문서를 넣어 어떤 자바 메모리 모델을 물었다 )

2 용액으로서 사용될 수있는 세 가지 특성에 "범용"으로 나타나는 경우는 자성, 순서 시정을 요구하도록하는 방식으로 잠금 동기화. 실제로, 동시성 제어 작업의 대부분은 동기화하여 수행 할 수 있습니다. 그리고 누군가가, 예 동기화 그에게 발행 된 문서를 넣어 무엇을 요구합니다.

. (3) 전에 가변 휘발성 방식의 동작 후에 휘발성 메모리 배리어를 삽입하여, 동시 및 질서 변수중인 장면의 가시성을 보장한다. 그리고 누군가가 휘발성이 문서는 또한 그에게 보냈 음을 무엇인지를 묻는

4, 휘발성 키워드는 원 자성을 보장하고, monitorenter에 의해 동기화 및 두 개의 명령어가 다중 CPU의 타임 슬라이스 발생하지 않도록 만, 동시에 하나의 스레드가 액세스 할 수있는 수정 된 코드를 확인하기 위해 동기화 될 수있다 monitorexit 수 없습니다 스레드 사이의 전환, 원 자성을 보장 할 수 있습니다. 결국 멀티 쓰레딩 자바 병행 프로그래밍은 아이들이 얼마나입니까?

음, 우리는 동기화, 알고 휘발성이 개 키워드는 두 가지 핵심 자바 병행 프로그래밍으로 자주 사용하고, 이전 검토에 의해, 우리가 알 수있는 자성, 가시성을 표시하지 않을 것이다 동기 동시 프로그래밍을 보장하고 , 문제를 주문하고, 휘발성는 가시성과 질서, 다음 보장 할 수 모두 HE Sheng의 휘발성 동기화 탄생?

동기화 문제

잠겨 있기 때문에 우리 모두는, 그것은 자연, 즉 동기화 잠금 장치의 일종이다 알고있는 다음과 같은 단점이 있습니다 :

1, 성능 손실이

JDK 1.6 비록 이러한 적응 스핀 잠금 제거, 잠금 조, 경량 잠금 장치로, 최적화를 많이 수행 동기화 (바이어스를 고정 멀티 스레드 (오)에 대한 심층적 인 이해 - 자바 가상 머신 최적화 된 잠금 기술 ), 그러나 결국 그는 또한 잠금입니다.

최적화 이러한 유형보다도, 모든 모니터 (피하는 방법 찾으려고 멀티 스레드 (사에 대한 심층적 인 이해) - 원칙 Moniter의 실현 ) 잠겨을, 모든 경우는 아니지만 심지어 최적화 후, 또한 최적화 할 수 있습니다, 최적화 과정은 일정 시간이 소요됩니다.

따라서, 동기 로크 전에 수행되는 동기 또는 동기 블록의 방법 또는 동작을 사용할지, 동기화 동작이 필요하면이 로킹 프로세스를 해제하는 것은 성능의 손실을 가지고있다 해제.

많은 가상 머신의 제거로 인해 둘 사이의 성능 비교, 소개하고 둘 사이의 성능 차이를 정량화하기 어렵지만, 우리는 기본 원칙을 확인할 수 있습니다 잠금의 구현을 최적화, 그래서 것은 : 읽기 작업 휘발성 변수의 성능 트럼펫 일반적인 변수는 대부분의 장면에서 휘발성 잠금 오버 헤드보다 낮은 때문에 그렇다고하더라도, 그것은 느려집니다 메모리 장벽을 삽입 할 필요가 거의 차이,하지만 쓰기 작업을하지 않습니다.

막힘 결과 2

우리는에서 멀티 스레드 (A)의 -depth 이해 -의 원칙의 동기화 실현 이 monitorenter을 ACC_SYNCHRONIZED되는 동기화 방법이나 동기화 된 블록 여부, 또는 여부를 동기화 관련하여 도입 원칙의 실현, monitorexit는 모니터 구현을 기반으로합니다.

여러 스레드가 소유자 지역이 될 수있는 락 객체를 취득 스레드가있을 때 첫째, 항목 설정을 입력합니다, 동기화 코드에 액세스 할 때 모니터 개체를 기반으로, 다른 스레드는 항목 설정을 기다릴 것입니다. 스레드가 호출 할 때 그리고 대기 방법은 잠금을 해제하고 대기 설정 대기를 입력합니다.

따라서, 로크는 본질적으로 블로킹 잠금 동기화를 달성하고, 이는 다수의 스레드가 동일한 공유 객체를 액세스 큐이다.

휘발성이 Java 가상 머신에 의해 제공되는 경량 동기화 메커니즘, 그는 달성하는 메모리 배리어에 기초한다. 결국, 그는 고정되지 않은, 그래서 그는 동기에 의한 차단 문제 및 성능 손실이 없습니다.

휘발성 추가 기능

휘발성 언급 이전에 더하여 우리는 동기화 성능보다 더 휘발성 또한,이 명령의 재 배열이 금지 된 좋은 또한있다.

의는, 예를 취할 경우에만 일어날 휘발성 문제를 사용하지 않고 동기화하는 경우를 살펴 보자, 우리는 더 익숙한 단일 케이스 모델 실행했다.

우리는 여기에서 휘발성 키워드를 사용하지 않는 두 번 확인 잠금의 방법으로 싱글을 달성 :

 1   public class Singleton {  
 2      private static Singleton singleton;  
 3       private Singleton (){}  
 4       public static Singleton getSingleton() {  
 5       if (singleton == null) {  
 6           synchronized (Singleton.class) {  
 7               if (singleton == null) {  
 8                   singleton = new Singleton();  
 9               }  
 10           }  
 11       }  
 12       return singleton;  
 13       }  
 14   }  
复制代码

상기 코드는 우리가 고정되도록 동기화하여 Singleton.class, 만약 하나 개의 스레드 만 콘텐츠 동기 부호 블록을 실행할 수있는 동시에 보장 할 수, 즉 단일 새로운 싱글 () 번 실행될이 동작이다 = 어느 그것은 싱글 톤을 구현합니다.

우리가 코드에서 상기 실시 예를 하나의 객체를 사용하는 경우에는, 가능한 NULL 포인터 예외가 발생한다. 이것은 오히려 이상한 상황이다.

우리는 가정이 Thread1하고 Thread2 두 개의 스레드가 동시에 Singleton.getSingleton 방법을 요청할 때 :

1 단계는도 8에 광고 Thread1 실행은 객체를 초기화한다. 2 단계는, Thread2 ==는 그것이 단일 결정하고, 널을 라인 (5)을 수행한다. 3 단계, Thread2 판사는 싱글을 발견 한 후! 라인 (12)의 구현되도록 = NULL은 단일 복귀. 4 단계 후에, Thread2는 단일 개체는 () 호출 singleton.call 후속 작업을 실행하기 시작하세요.

위의 과정은 문제를 보이지 않았지만, 사실, 4 단계, Thread2에서 singleton.call을 (호출 할 때), 그리고 널 포인터 예외를 던질 수있다.

3 단계, Thread2는 싱글 톤 객체가 완전한 객체가 아닌 얻을 수 있기 때문에 모든는 NPE에서 발생합니다.

우리는 분석 여기에 있습니다, 싱글 톤 = 새로운 싱글 톤 (); 뭔가를 할 결국 코드 행은 대략 다음과 같다 :

1, 새로운 가상 명령, 상수 풀에 기회가 클래스 참조의 기호를 찾습니다. 도 2에서, 참조 기호에 의해 표현되는 클래스가로드 파싱 초기화 여부를 확인한다. 객체에 할당 된 3 가상 머신 메모리. (4)는 모든 할당 된 가상 머신의 메모리 공간은 0 값으로 초기화. 5, 가상 머신은 필요한 설정을 대상으로한다. 도 6의 구현 방법은, 멤버 변수가 초기화된다. 도 7에서, 객체의 메모리 영역에 대한 참조.

우리는 세 가지 단계로 단순화 단순화이 과정에서 보면 :

A, JVM은 메모리 객체 M B를 할당, 메모리 M에 객체를 초기화 c는, 복사 메모리 M 싱글 변수 어드레스

싱글 변수에 할당 된 메모리 주소가 단계 전에 Thread1 그래서 마지막 단계이기 때문에, Thread2 싱글을위한 == null이 판사는 항상 참이었다, 그는이 차단 된 것,이 단계는 Thread1 때까지 실행됩니다있다으로 완료했다.

그러나, 상기 방법은 원자 동작되지 않고, 상기 한 단계로 재 배열되는 경우, 컴파일러가 재 배열 될 수있다 :

A, JVM은 메모리 객체 M C, 복사 메모리 싱글 변수 B의 주소를 메모리 M에 객체로 초기화 할당

이 경우, Thread1 객체를 초기화 제 실행으로 메모리 할당, 가변 할당을 수행하고, 마지막으로 실행되며, 그 후, 그 Thread1 객체를 초기화 할 때, 말하자면, Thread2는 == NULL의 전진을 얻을 수 판정 싱글 올 그는 초기화를 완료하지 않았기 때문에 거짓, 그것은 불완전한 sigleton 개체를 반환합니다.

이러한 상황이 발생하면, 우리는 가능성이 매우 높은 NPE 예외 때이 객체를 사용하려고 불완전한 단일 객체를 얻는다.

그럼, 어떻게이 문제를 해결하기 위해? 명령어의 재 배열이 질문에 이르게하기 때문에, 줄에 명령 재 배열을 피할 것.

휘발성이 지침의 재 배열을 피할 수 있기 때문에 그래서, 휘발성이 편리합니다. 코드에 다음 코드, 우리는이 문제를 해결할 수있는 한 :

 1   public class Singleton {  
 2      private volatile static Singleton singleton;  
 3       private Singleton (){}  
 4       public static Singleton getSingleton() {  
 5       if (singleton == null) {  
 6           synchronized (Singleton.class) {  
 7               if (singleton == null) {  
 8                   singleton = new Singleton();  
 9               }  
 10           }  
 11       }  
 12       return singleton;  
 13       }  
 14   }  
复制代码

휘발성 싱글의 사용에 제약 그의 지시 초기화 과정이 재 배열되지 않도록합니다.

질서의 보장을 동기화?

왜 여기없는 것, 즉 그것의 질서를 보장하기 위해 동기화 할 수 대답 위의 모든 문제 또는 주문 문제 후, 물을 것이다 친구가 여기를 참조하십시오?

첫째, 점은 분명하다 : 동기화 된 프로세서 명령 재 배열 및 최적화를 금지하지 않습니다 . 그리고는 그것의 질서를 보장하는 방법은?

이는 조금 더 주문의 개념을 확장합니다. 자연 순서 자바 프로그램은 한 문장으로 요약 될 수있다 :이 스레드에서 보면, 모든 작업은 자연 질서이다. 당신이 스레드에서 다른 스레드를 보면, 모든 작업은 순서가 있습니다.

이 문장은 원래 문장에서 "Java 가상 머신에 대한 깊이있는 이해를"더이지만, 그것을 어떻게 이해? 저우 밍없이 자세한 설명. 여기에 나는이 사실의 단순한 확장에보고, 관련 AS-경우 시리얼 의미.

-IF로 직렬 의미하는 뜻을 의미한다 : 아무리 단일 스레드 프로그램의 결과를 변경하는 방법을 재 배열하지 않는다. 컴파일러 및 프로세서 최적화 어쨌든, AS-경우 직렬 의미 준수해야합니다.

상세 레이아웃으로-IF 직렬 의미 여기서, 단순히, 같은-IF 직렬 의미는 단일 스레드가 아무리 지시 재배치, 구현의 최종 결과가 어떻게 변화하지 수 없도록 없다.

컴파일러는 AS-경우 직렬 의미에 부합되므로,이 최적화 어떤 문제가 없기 때문에 그래서, 우리가 잠금을 확인보기의 단일 스레드 지점 서 두 배로 예제로 돌아가, 즉, 그것을보고 Thread1입니다, 이 스레드의 실행 결과에 대한 영향을주지 않습니다.

그러나, 명령의 내부 재 배열이 Thread1 Thread2에 미치는 영향을 알려줍니다.

그래서, 우리는 질서가 즉, 여러 스레드 간의 질서 보장하기 위해 동기화 위해 여러 스레드에 의해 실행되는 컨텐츠를 잠겨 있음을 말할 수있다. 그러나 내부 동기화 코드 또는 재정렬이 발생하지만, 컴파일러와 프로세서는 다음과 때문에있는 그대로의 경우 직렬 의미론은, 그래서 우리는 이러한 단일 스레드 내에서 재정렬을 무시 될 수 있음을 말할 수있다.

개요

이 논문은 휘발성으로 바꾸어 놓을 수없는 두 가지 측면의 중요성에 대해 설명합니다 :

한 가지 이유는 잠금 장치가 동기화되어 있는지가 차단 및 성능 문제,하지만 휘발성이 잠겨 있지, 그래서 차단 및 성능 문제이다.

한편, 장벽에 의한 휘발성 메모리는 자신의 가시성 및 순서 문제를 해결하는 데 도움이, 그리고 메모리 장벽의 사용은 또한 첨부에게 disable 명령의 재 배열을 제공합니다, 그래서 몇 가지 시나리오를 피할 수 있기 때문에 문제는 명령 재 배열에서 발생합니다.

추천

출처juejin.im/post/5d5c9fbce51d4561cd246641