답변:
짧은 대답은 : 아니요.
로부터 java.util.concurrent.atomic
패키지 설명서를 참조하십시오. 인용 :
원자의 접근 및 업데이트에 대한 메모리 효과는 일반적으로 휘발성 물질에 대한 규칙을 따릅니다.
get
volatile
변수 를 읽는 메모리 효과가 있습니다.set
volatile
변수 쓰기 (할당)의 메모리 효과가 있습니다.
그건 그렇고, 그 문서는 매우 훌륭하며 모든 것이 설명되어 있습니다.
AtomicReference::lazySet
volatile
변수를 통해 얻을 수없는 의미를 가진 최신 (Java 6+) 작업이 도입되었습니다 . 자세한 내용은 이 게시물 을 참조하십시오.
몇 가지 차이점과 장단점이 있습니다.
AtomicReference
get / set을 사용하면 (javadoc 상태와 같이) 휘발성 필드 와 동일한 JMM 시맨틱이 있지만 AtomicReference
참조 주위의 래퍼이므로 필드에 액세스하려면 추가 포인터 추적이 필요 합니다.
메모리 공간이 승산된다 (대부분의 VM에서 참 압축 죄송 환경을 가정)
AtomicReference
= 4b + 16b (12b 객체 헤더 + 4b 참조 필드)AtomicReference
휘발성 참조보다 풍부한 API를 제공합니다. 을 사용 AtomicFieldUpdater
하거나 Java 9 a 를 사용하여 휘발성 참조에 대한 API를 다시 얻을 수 있습니다 VarHandle
. sun.misc.Unsafe
가위로 달리기를 좋아한다면 똑바로 닿을 수도 있습니다 . AtomicReference
자체는를 사용하여 구현됩니다 Unsafe
.
따라서 언제 다른 것을 선택하는 것이 좋습니까?
AtomicReference
/ AtomicFieldUpdater
/ 중에서 선택 Unsafe
하십시오. 민감한 지역이 아니라면 가십시오 AtomicReference
. 라이브러리 작성자는 일반적으로 대상 JDK, 예상 API 제한, 메모리 제한 등에 따라 이러한 방법을 혼합하여 사용합니다.JDK 소스 코드 는 이와 같은 혼란에 대답하는 가장 좋은 방법 중 하나입니다. AtomicReference의 코드를 보면 객체 저장에 volatie 변수를 사용합니다.
private volatile V value;
따라서 AtomicReference에서 get () 및 set ()을 사용하려는 경우 휘발성 변수를 사용하는 것과 같습니다. 그러나 다른 독자들이 언급했듯이 AtomicReference는 추가적인 CAS 의미를 제공합니다. 따라서 먼저 CAS 의미를 원하는지 여부를 결정하고 AtomicReference 만 사용하십시오.
AtomicReference
일반 휘발성 변수가 제공하지 않는 추가 기능을 제공합니다. API Javadoc을 읽었을 때 이것을 알 수 있지만 일부 작업에 유용한 잠금도 제공합니다.
그러나이 추가 기능이 필요하지 않으면 일반 volatile
필드 를 사용하는 것이 좋습니다 .
volatile
필드는 일반 필드처럼 사용할 수 있지만 AtomicReference
요구 사항 get
및 set
방법 의 값에 액세스합니다 .
때때로 가져 오기 및 설정 만 사용하더라도 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;
그러나 두 번째 코드는 미래에 "코드 정리"중에 누군가 실수로 제거 될 가능성이 높습니다.