[java] 휘발성 키워드가 유용한 이유

오늘 직장에서 저는 volatile키워드를 Java로 보았습니다. 그것에 익숙하지 않아서이 설명을 찾았습니다.

자바 이론 및 실습 : 변동성 관리

해당 기사에서 해당 키워드에 대해 자세히 설명 했으므로 키워드를 사용하거나 올바른 방식으로이 키워드를 사용할 수있는 사례를 볼 수 있습니까?



답변

volatile메모리 가시성에 대한 의미가 있습니다. 기본적으로 volatile필드 값은 쓰기 작업이 완료된 후 모든 독자 (특히 다른 스레드)에게 표시됩니다. 이 없으면 volatile독자는 업데이트되지 않은 값을 볼 수 있습니다.

귀하의 질문에 대답하기 위해 : 예, volatile변수를 사용하여 일부 코드가 루프를 계속하는지 여부를 제어합니다. 루프는 volatile값을 테스트하고 값이 계속되면 계속합니다 true. false“stop”메소드를 호출하여 조건을 설정할 수 있습니다 . 루프는 falsestop 메소드가 실행을 완료 한 후 값을 테스트 할 때보고 종료합니다.

제가 추천하는 ” 실제로 Java Concurrency “책에 대한 좋은 설명이 volatile있습니다. 이 책은 질문에서 언급 된 IBM 기사를 쓴 동일한 사람이 작성했습니다 (사실, 해당 기사의 맨 아래에 그의 책을 인용합니다). 필자가 사용하는 volatile기사는 “패턴 1 상태 플래그”라고합니다.

volatile후드 아래에서 작동 하는 방법에 대한 자세한 내용을 보려면 Java 메모리 모델을 읽으십시오 . 이 수준을 넘어서려면 Hennessy & Patterson 과 같은 훌륭한 컴퓨터 아키텍처 책을 확인하고 캐시 일관성 및 캐시 일관성에 대해 읽으십시오.


답변

“… 휘발성 수정자는 필드를 읽는 스레드가 가장 최근에 작성된 값을 볼 수 있도록 보장합니다.” -Josh Bloch

사용 volatile에 대해 생각하고 있다면 java.util.concurrent원자 행동을 다루는 패키지 를 읽으십시오 . 싱글 톤 패턴

에 대한 Wikipedia 게시물 은 사용 중입니다.


답변

에 대한 중요한 점 volatile:

  1. 자바의 동기화는 자바 키워드를 사용하여 가능 synchronized하고 volatile및 잠금.
  2. Java에서는 synchronized변수를 가질 수 없습니다 . 사용 synchronized변수와 키워드 불법 컴파일 오류가 발생합니다. synchronizedJava 에서 변수 를 사용하는 대신 java volatile변수를 사용하면 JVM 스레드가 volatile기본 메모리에서 변수 값을 읽고 로컬로 캐시하지 않도록 지시 할 수 있습니다.
  3. 변수가 여러 스레드간에 공유되지 않으면 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가 손상되면 다른 모든 스레드는 _instancenull이 아닌 값을 볼 수 없으며 여전히 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을 사용할 수 있습니다. 휘발성으로 표시된 변수는 객체 생성자가 실행을 마치면 다른 스레드에서만 볼 수 있습니다.
출처

여기에 이미지 설명을 입력하십시오

volatileJava 사용법 :

페일 패스트 반복기는 일반적으로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키워드로 선언 된 변수 에는 두 가지 주요 특성이있어 특별합니다.

  1. 휘발성 변수가 있으면 스레드가 컴퓨터의 (마이크로 프로세서) 캐시 메모리에 캐시 할 수 없습니다. 액세스는 항상 주 메모리에서 발생했습니다.

  2. 휘발성 변수에 대한 쓰기 작업 이 있고 갑자기 읽기 작업 이 요청되면 읽기 작업 이전에 쓰기 작업이 완료됩니다 .

위의 두 가지 특성으로 인해

  • 휘발성 변수를 읽는 모든 스레드는 확실히 최신 값을 읽습니다. 캐시 된 값은이를 오염시킬 수 없기 때문입니다. 또한 읽기 요청은 현재 쓰기 작업이 완료된 후에 만 ​​부여됩니다.

반면에

  • 위에서 언급 한 # 2 를 자세히 조사하면 volatile키워드가 ‘n’개의 판독기 스레드와 하나의 기록기 스레드 만 있는 공유 변수를 유지하는 이상적인 방법 임을 알 수 있습니다 . volatile키워드를 추가하면 완료됩니다. 스레드 안전에 대한 다른 오버 헤드가 없습니다.

반대로

우리 volatile 키워드를 단독으로 사용할 수 없으며 , 액세스하는 작성자 스레드둘 이상인 공유 변수를 만족시킬 수 없습니다 .


답변

long 및 double 변수 유형에 대한 읽기 및 쓰기 작업 처리에 대해서는 아무도 언급하지 않았습니다. 읽기 및 쓰기는 volatile 키워드를 원자 연산으로 사용해야하는 long 및 double 변수 유형을 제외하고 참조 변수 및 대부분의 원시 변수에 대한 원자 연산입니다. @링크