Respuestas:
La respuesta corta es: No.
De la java.util.concurrent.atomicdocumentación del paquete. Citar:
Los efectos de memoria para accesos y actualizaciones de atómicos generalmente siguen las reglas para volátiles:
gettiene los efectos de memoria de leer unavolatilevariable.settiene los efectos de memoria de escribir (asignar) unavolatilevariable.
Por cierto, esa documentación es muy buena y todo está explicado.
AtomicReference::lazySetes una nueva operación (Java 6+) introducida que tiene una semántica inalcanzable a través de volatilevariables. Vea esta publicación para más información.
Hay varias diferencias y compensaciones:
El uso de un AtomicReferenceget / set tiene la misma semántica JMM que un campo volátil (como indica el javadoc), pero AtomicReferencees un contenedor alrededor de una referencia, por lo que cualquier acceso al campo implica una búsqueda de puntero adicional .
La huella de memoria se multiplica (suponiendo un entorno OOP comprimido, lo cual es cierto para la mayoría de las máquinas virtuales):
AtomicReference = 4b + 16b (encabezado de objeto 12b + campo de referencia 4b)AtomicReferenceofrece una API más rica que una referencia volátil. Puede recuperar la API para la referencia volátil utilizando un AtomicFieldUpdatero con Java 9 a VarHandle. También puedes alcanzarlo directamente sun.misc.Unsafesi te gusta correr con unas tijeras. AtomicReferencese implementa usando Unsafe.
Entonces, ¿cuándo es bueno elegir uno sobre el otro?
AtomicReference/ AtomicFieldUpdater/ Unsafedonde tiende a pagar en legibilidad y riesgo para su ganancia de rendimiento. Si esta no es un área sensible, simplemente busque AtomicReference. Los escritores de bibliotecas suelen utilizar una combinación de estos métodos según los JDK específicos, las restricciones API esperadas, las restricciones de memoria, etc.El código fuente JDK es una de las mejores formas de responder a confusiones como esta. Si observa el código en AtomicReference, utiliza una variable de volatilidad para el almacenamiento de objetos.
private volatile V value;
Entonces, obviamente, si va a usar get () y set () en AtomicReference, es como usar una variable volátil. Pero como comentaron otros lectores, AtomicReference proporciona semántica CAS adicional. Por lo tanto, primero decida si desea la semántica de CAS o no, y si solo lo desea, use AtomicReference.
AtomicReferenceproporciona funcionalidad adicional que una variable volátil simple no proporciona. Como haya leído el Javadoc API, lo sabrá, pero también proporciona un bloqueo que puede ser útil para algunas operaciones.
Sin embargo, a menos que necesite esta funcionalidad adicional, le sugiero que use un volatilecampo simple .
volatilecampo se puede usar como cualquier campo normal, mientras que para acceder al valor en un se AtomicReferencerequiere revisar gety setmétodos.
A veces, incluso si solo usa gets y sets, AtomicReference puede ser una buena opción:
Ejemplo con volátil:
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
}
}
La implementación con AtomicReference le proporcionaría una sincronización de copia en escritura de forma gratuita.
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
}
}
Se podría decir que aún podría tener una copia adecuada si sustituye:
Status status = statusWrapper.get();
con:
Status statusCopy = status;
Sin embargo, es más probable que alguien elimine el segundo accidentalmente en el futuro durante la "limpieza del código".