[java] Java 휘발성 참조 대 AtomicReference

volatileObject 참조와 AtomicReference내가 사용하는 경우 get()set()-methods from 사이에 차이점이 AtomicReference있습니까?



답변

짧은 대답은 : 아니요.

로부터 java.util.concurrent.atomic패키지 설명서를 참조하십시오. 인용 :

원자의 접근 및 업데이트에 대한 메모리 효과는 일반적으로 휘발성 물질에 대한 규칙을 따릅니다.

  • getvolatile변수 를 읽는 메모리 효과가 있습니다.
  • setvolatile변수 쓰기 (할당)의 메모리 효과가 있습니다.

그건 그렇고, 그 문서는 매우 훌륭하며 모든 것이 설명되어 있습니다.


AtomicReference::lazySetvolatile변수를 통해 얻을 수없는 의미를 가진 최신 (Java 6+) 작업이 도입되었습니다 . 자세한 내용은 이 게시물 을 참조하십시오.


답변

아니 없어.

AtomicReference가 제공하는 추가 기능은 compareAndSet () 메서드와 친구입니다. 이러한 메소드가 필요하지 않은 경우, 휘발성 참조는 AtomicReference.set () 및 .get ()과 동일한 의미를 제공합니다.


답변

몇 가지 차이점과 장단점이 있습니다.

  1. AtomicReferenceget / set을 사용하면 (javadoc 상태와 같이) 휘발성 필드 와 동일한 JMM 시맨틱이 있지만 AtomicReference참조 주위의 래퍼이므로 필드에 액세스하려면 추가 포인터 추적이 필요 합니다.

  2. 메모리 공간이 승산된다 (대부분의 VM에서 참 압축 죄송 환경을 가정)

    • 휘발성 기준 = 4b
    • AtomicReference = 4b + 16b (12b 객체 헤더 + 4b 참조 필드)
  3. AtomicReference휘발성 참조보다 풍부한 API를 제공합니다. 을 사용 AtomicFieldUpdater하거나 Java 9 a 를 사용하여 휘발성 참조에 대한 API를 다시 얻을 수 있습니다 VarHandle. sun.misc.Unsafe가위로 달리기를 좋아한다면 똑바로 닿을 수도 있습니다 . AtomicReference자체는를 사용하여 구현됩니다 Unsafe.

따라서 언제 다른 것을 선택하는 것이 좋습니까?

  • get / set 만 필요하십니까? 휘발성 필드, 가장 간단한 솔루션 및 가장 낮은 오버 헤드를 고수하십시오.
  • 추가 기능이 필요하십니까? 이것이 코드의 성능 (속도 / 메모리 오버 헤드)에 민감한 부분 이라면 가독성을 높이고 성능 향상 위험을 감수하는 AtomicReference/ AtomicFieldUpdater/ 중에서 선택 Unsafe하십시오. 민감한 지역이 아니라면 가십시오 AtomicReference. 라이브러리 작성자는 일반적으로 대상 JDK, 예상 API 제한, 메모리 제한 등에 따라 이러한 방법을 혼합하여 사용합니다.

답변

JDK 소스 코드 는 이와 같은 혼란에 대답하는 가장 좋은 방법 중 하나입니다. AtomicReference의 코드를 보면 객체 저장에 volatie 변수를 사용합니다.

private volatile V value;

따라서 AtomicReference에서 get () 및 set ()을 사용하려는 경우 휘발성 변수를 사용하는 것과 같습니다. 그러나 다른 독자들이 언급했듯이 AtomicReference는 추가적인 CAS 의미를 제공합니다. 따라서 먼저 CAS 의미를 원하는지 여부를 결정하고 AtomicReference 만 사용하십시오.


답변

AtomicReference일반 휘발성 변수가 제공하지 않는 추가 기능을 제공합니다. API Javadoc을 읽었을 때 이것을 알 수 있지만 일부 작업에 유용한 잠금도 제공합니다.

그러나이 추가 기능이 필요하지 않으면 일반 volatile필드 를 사용하는 것이 좋습니다 .


답변

때때로 가져 오기 및 설정 만 사용하더라도 AtomicReference가 좋은 선택 일 수 있습니다.

휘발성이있는 예 :

private volatile Status status;
...
public setNewStatus(Status newStatus){
  status = newStatus;
}

public void doSomethingConditionally() {
  if(status.isOk()){
    System.out.println("Status is ok: " + status); // here status might not be OK anymore because in the meantime some called setNewStatus(). setNewStatus should be synchronized
  }
}

AtomicReference를 사용한 구현은 복사 중 복사 동기화를 무료로 제공합니다.

private AtomicReference<Status> statusWrapper;
...

public void doSomethingConditionally() {
  Status status = statusWrapper.get();
  if(status.isOk()){
    System.out.println("Status is ok: " + status); // here even if in the meantime some called setNewStatus() we're still referring to the old one
  }
}

대체 한 경우 여전히 올바른 사본을 가질 수 있다고 말할 수 있습니다.

Status status = statusWrapper.get();

와:

Status statusCopy = status;

그러나 두 번째 코드는 미래에 “코드 정리”중에 누군가 실수로 제거 될 가능성이 높습니다.


답변