Java 휘발성 키워드
Java 스레드 동시성 처리에서 키워드 휘발성을 사용하는 데 많은 혼란이 있습니다. 이 키워드를 사용하면 다중 스레드 동시성 처리를 사용할 때 모든 것이 잘 될 수 있다고 생각합니다.
Java 언어는 멀티 스레딩을 지원합니다. 스레드 동시성 문제를 해결하기 위해 언어 내부에 동기 블록 및 휘발성 키워드 메커니즘이 소개됩니다.
동기화
모든 사람은 동기화 된 블록에 익숙하며 동기화 된 키워드를 통해 구현됩니다. 동기화 및 블록 문을 사용하면 멀티 스레드에 액세스 할 때 동시에 하나의 스레드 만 사용할 수 있습니다.
동기화 된 수정 된 메소드 또는 코드 블록.
휘발성 물질
휘발성으로 수정 된 변수의 경우 스레드는 변수를 사용할 때마다 변수의 가장 수정 된 값을 읽습니다. 휘발성은 쉽게 오용되어 원자 연산에 사용됩니다.
아래 예를 봅시다. 우리는 카운터를 구현합니다. 스레드가 시작될 때마다 Counter Inc 메소드가 호출되어 카운터에 하나를 추가합니다.
실행 환경 -JDK 버전 : JDK1.6.0_31, 메모리 : 3G CPU : X86 2.4G
공개 클래스 카운터 {public static int count = 0; public static void inc () {// 여기 지연은 1 밀리 초이며 결과는 {thread.sleep (1); } catch (InterruptedException e) {} count ++; } public static void main (string [] args) {// i ++ 계산을 수행하고 (int i = 0; i <1000; i ++) {new 스레드 (new runnable () {@override public void Run () {counter.inc ();}})에 대한 실제 결과를 확인하기 위해 동시에 1000 개의 스레드를 시작합니다. } // 여기에서 실행되는 각 실행 값은 다를 수 있습니다. }}运行结果:Counter.count= 995
实际运算结果每次可能都不一样,本机的结果为:运行结果:Counter.count= 995 ,可以看出,在多线程的环境下,Counter.count并没有期望结果是1000
많은 사람들은 이것이 다중 스레드 동시성 문제라고 생각합니다. 이 문제를 피하기 위해很多人以为,这个是多线程并发问题,只需要在变量count之前加上volatile 추가하면됩니다就可以避免这个问题,那我们在修改代码看看,看看结果是不是符合我们的期望
공개 클래스 카운터 {공개 휘발성 정적 int count = 0; public static void inc () {// 여기 지연은 1 밀리 초이며 결과는 {thread.sleep (1); } catch (InterruptedException e) {} count ++; } public static void main (string [] args) {// 동시에 1000 스레드를 시작하고 i ++ 계산을 수행하고 (int i = 0; i <1000; i ++) {new 스레드 (new Runnable () {@override public void run () {counter.inc ();}})에 대한 실제 결과를 참조하십시오. } // 여기에서 실행되는 각 실행 값은 다를 수 있습니다. 아마도 1000 System.out.println ( "실행 결과 : count.count =" + counter.count); }}실행 결과 : counter.count = 992
작업 결과는 여전히 우리가 예상했던 것보다 1000이 아닙니다. 아래 이유를 분석 해 봅시다
Java Garbage Collection 기사에서 JVM의 순간에 메모리 할당이 설명되어 있습니다. 메모리 영역 중 하나는 JVM 가상 머신 스택이며 각 스레드에는 실행될 때 스레드 스택이 있습니다.
스레드 스택은 스레드 런타임 중에 가변 값 정보를 저장합니다. 스레드가 특정 객체의 값에 액세스하면 먼저 객체의 참조를 통해 힙 메모리에 해당하는 변수의 값을 찾은 다음 힙 메모리를 넣습니다.
변수의 특정 값은 스레드의 로컬 메모리에로드되며 변수의 사본이 생성됩니다. 그 후, 스레드는 더 이상 힙 메모리에서 객체의 변수 값과 관계가 없지만 사본 변수의 값을 직접 수정합니다.
수정 후 특정 순간에 (스레드가 종료되기 전), 스레드 변수 사본의 값은 힙의 객체 변수로 자동으로 기록됩니다. 이렇게하면 힙 내 물체의 값이 변경됩니다. 다음 그림
이 글쓰기 상호 작용을 설명하십시오
기본 메모리에서 현재 작업 메모리까지 복사 변수를 읽고로드합니다.
공유 변수 값을 변경하려면 실행 코드 사용 및 할당
작업 메모리 데이터로 새로 고침 메인 메모리 관련 콘텐츠를 저장 및 쓰기
사용 및 할당이 여러 번 나타날 수 있습니다
그러나 이러한 작업은 원자가 아니며, 즉 읽기 부하 후, 메인 메모리 수 변수가 수정되면 스레드 작업 메모리의 값이로드 된 이후 해당 변경 사항을 유발하지 않으므로 계산 된 결과는 예상과 다릅니다.
휘발성에 의해 수정 된 변수의 경우 JVM 가상 머신은 기본 메모리에서 스레드 작업 메모리로로드 된 값이 최신임을 보장합니다.
예를 들어, 스레드 1과 스레드 2가 읽기 및로드 작업을 수행하고 메인 메모리의 카운트 값이 5라는 것을 알면 최신 값이로드됩니다.
힙 계수가 스레드 1에서 수정되면 주 메모리에 기록되며 기본 메모리의 카운트 변수는 6이됩니다.
스레드 2는 이미 읽기 및로드 작업을 수행 했으므로 메인 메모리 카운트의 변수 값도 작업 후 6으로 업데이트됩니다.
이로 인해 두 개의 스레드가 휘발성 키워드를 제 시간에 수정 한 후 동시성이 발생합니다.
읽어 주셔서 감사합니다. 도움이되기를 바랍니다. 이 사이트를 지원 해주셔서 감사합니다!