[java] 휘발성 키워드가 유용한 이유
오늘 직장에서 저는 volatile
키워드를 Java로 보았습니다. 그것에 익숙하지 않아서이 설명을 찾았습니다.
해당 기사에서 해당 키워드에 대해 자세히 설명 했으므로 키워드를 사용하거나 올바른 방식으로이 키워드를 사용할 수있는 사례를 볼 수 있습니까?
답변
volatile
메모리 가시성에 대한 의미가 있습니다. 기본적으로 volatile
필드 값은 쓰기 작업이 완료된 후 모든 독자 (특히 다른 스레드)에게 표시됩니다. 이 없으면 volatile
독자는 업데이트되지 않은 값을 볼 수 있습니다.
귀하의 질문에 대답하기 위해 : 예, volatile
변수를 사용하여 일부 코드가 루프를 계속하는지 여부를 제어합니다. 루프는 volatile
값을 테스트하고 값이 계속되면 계속합니다 true
. false
“stop”메소드를 호출하여 조건을 설정할 수 있습니다 . 루프는 false
stop 메소드가 실행을 완료 한 후 값을 테스트 할 때보고 종료합니다.
제가 추천하는 ” 실제로 Java Concurrency “책에 대한 좋은 설명이 volatile
있습니다. 이 책은 질문에서 언급 된 IBM 기사를 쓴 동일한 사람이 작성했습니다 (사실, 해당 기사의 맨 아래에 그의 책을 인용합니다). 필자가 사용하는 volatile
기사는 “패턴 1 상태 플래그”라고합니다.
volatile
후드 아래에서 작동 하는 방법에 대한 자세한 내용을 보려면 Java 메모리 모델을 읽으십시오 . 이 수준을 넘어서려면 Hennessy & Patterson 과 같은 훌륭한 컴퓨터 아키텍처 책을 확인하고 캐시 일관성 및 캐시 일관성에 대해 읽으십시오.
답변
“… 휘발성 수정자는 필드를 읽는 스레드가 가장 최근에 작성된 값을 볼 수 있도록 보장합니다.” -Josh Bloch
사용 volatile
에 대해 생각하고 있다면 java.util.concurrent
원자 행동을 다루는 패키지 를 읽으십시오 . 싱글 톤 패턴
답변
에 대한 중요한 점 volatile
:
- 자바의 동기화는 자바 키워드를 사용하여 가능
synchronized
하고volatile
및 잠금. - Java에서는
synchronized
변수를 가질 수 없습니다 . 사용synchronized
변수와 키워드 불법 컴파일 오류가 발생합니다.synchronized
Java 에서 변수 를 사용하는 대신 javavolatile
변수를 사용하면 JVM 스레드가volatile
기본 메모리에서 변수 값을 읽고 로컬로 캐시하지 않도록 지시 할 수 있습니다. - 변수가 여러 스레드간에 공유되지 않으면
volatile
키워드 를 사용할 필요가 없습니다 .
의 사용법 예 volatile
:
public class Singleton {
private static volatile Singleton _instance; // volatile variable
public static Singleton getInstance() {
if (_instance == null) {
synchronized (Singleton.class) {
if (_instance == null)
_instance = new Singleton();
}
}
return _instance;
}
}
우리는 첫 번째 요청이 올 때 게으른 인스턴스를 만들고 있습니다.
우리가하지 않으면 _instance
변수 volatile
의 인스턴스를 생성하는 스레드 다음을 Singleton
다른 스레드와 통신 할 수 없습니다. 따라서 스레드 A가 Singleton 인스턴스를 생성하고 생성 직후 CPU가 손상되면 다른 모든 스레드는 _instance
null이 아닌 값을 볼 수 없으며 여전히 null이 할당 된 것으로 간주합니다.
왜 이런 일이 발생합니까? 판독기 스레드는 잠금을 수행하지 않고 기록기 스레드가 동기화 된 블록에서 나올 때까지 메모리가 동기화 _instance
되지 않고 주 메모리에서 값 이 업데이트되지 않습니다. Java의 Volatile 키워드를 사용하면 Java 자체에서 처리되며 이러한 업데이트는 모든 독자 스레드에서 볼 수 있습니다.
결론 :
volatile
키워드는 스레드간에 메모리 내용을 전달하는 데에도 사용됩니다.
휘발성이없는 사용 예 :
public class Singleton{
private static Singleton _instance; //without volatile variable
public static Singleton getInstance(){
if(_instance == null){
synchronized(Singleton.class){
if(_instance == null) _instance = new Singleton();
}
}
return _instance;
}
위의 코드는 스레드로부터 안전하지 않습니다. 동기화 된 블록 내에서 인스턴스 값을 다시 한 번 확인하지만 (성능상의 이유로) JIT 컴파일러는 생성자가 실행을 마치기 전에 인스턴스에 대한 참조가 설정되는 방식으로 바이트 코드를 재 배열 할 수 있습니다. 이는 getInstance () 메소드가 완전히 초기화되지 않았을 수있는 오브젝트를 리턴 함을 의미합니다. 코드를 스레드로부터 안전하게 만들기 위해 인스턴스 변수에 Java 5부터 키워드 volatile을 사용할 수 있습니다. 휘발성으로 표시된 변수는 객체 생성자가 실행을 마치면 다른 스레드에서만 볼 수 있습니다.
출처
volatile
Java 사용법 :
페일 패스트 반복기는 일반적으로volatile
목록 객체 의 카운터를 사용하여 구현됩니다 .
- 목록이 업데이트되면 카운터가 증가합니다.
- 를 만들면
Iterator
카운터의 현재 값이Iterator
개체에 포함됩니다 . - 때
Iterator
동작이 수행되고, 상기 방법은 두 개의 카운터 값을 비교하고,이 슬로우ConcurrentModificationException
가 다르면.
페일 세이프 반복기의 구현은 일반적으로 경량입니다. 이들은 일반적으로 특정 목록 구현 데이터 구조의 속성에 의존합니다. 일반적인 패턴은 없습니다.
답변
volatile
스레드를 중지하는 데 매우 유용합니다.
자신의 스레드를 작성하는 것이 아니라 Java 1.6에는 멋진 스레드 풀이 많이 있습니다. 그러나 스레드가 필요한 경우 스레드를 중지하는 방법을 알아야합니다.
스레드에 사용하는 패턴은 다음과 같습니다.
public class Foo extends Thread {
private volatile boolean close = false;
public void run() {
while(!close) {
// do work
}
}
public void close() {
close = true;
// interrupt here if needed
}
}
위의 코드 세그먼트 close
에서 while 루프 의 스레드 읽기 는를 호출 하는 스레드 와 다릅니다 close()
. 휘발성이 없으면 루프를 실행하는 스레드가 변경 사항을 닫을 수 없습니다.
동기화가 필요없는 방법에 주목
답변
volatile
사용하는 일반적인 예 는 volatile boolean
변수를 플래그로 사용하여 스레드를 종료하는 것입니다. 스레드를 시작했는데 다른 스레드에서 안전하게 중단하려면 스레드가 주기적으로 플래그를 확인하도록 할 수 있습니다. 중지하려면 플래그를 true로 설정하십시오. 플래그를 작성하면 volatile
검사중인 스레드가 다음 번에 synchronized
블록을 사용할 필요없이 검사 할 때 설정되었음을 확인할 수 있습니다 .
답변
volatile
키워드로 선언 된 변수 에는 두 가지 주요 특성이있어 특별합니다.
-
휘발성 변수가 있으면 스레드가 컴퓨터의 (마이크로 프로세서) 캐시 메모리에 캐시 할 수 없습니다. 액세스는 항상 주 메모리에서 발생했습니다.
-
휘발성 변수에 대한 쓰기 작업 이 있고 갑자기 읽기 작업 이 요청되면 읽기 작업 이전에 쓰기 작업이 완료됩니다 .
위의 두 가지 특성으로 인해
- 휘발성 변수를 읽는 모든 스레드는 확실히 최신 값을 읽습니다. 캐시 된 값은이를 오염시킬 수 없기 때문입니다. 또한 읽기 요청은 현재 쓰기 작업이 완료된 후에 만 부여됩니다.
반면에
- 위에서 언급 한 # 2 를 자세히 조사하면
volatile
키워드가 ‘n’개의 판독기 스레드와 하나의 기록기 스레드 만 있는 공유 변수를 유지하는 이상적인 방법 임을 알 수 있습니다 .volatile
키워드를 추가하면 완료됩니다. 스레드 안전에 대한 다른 오버 헤드가 없습니다.
반대로
우리 는volatile
키워드를 단독으로 사용할 수 없으며 , 액세스하는 작성자 스레드 가 둘 이상인 공유 변수를 만족시킬 수 없습니다 .
답변
long 및 double 변수 유형에 대한 읽기 및 쓰기 작업 처리에 대해서는 아무도 언급하지 않았습니다. 읽기 및 쓰기는 volatile 키워드를 원자 연산으로 사용해야하는 long 및 double 변수 유형을 제외하고 참조 변수 및 대부분의 원시 변수에 대한 원자 연산입니다. @링크
