Referencia volátil de Java frente a referencia atómica

135

¿Hay alguna diferencia entre una volatilereferencia de objeto y AtomicReferenceen caso de que solo use get()y set()-methods from AtomicReference?

auramo
fuente

Respuestas:

114

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 una volatilevariable.
  • settiene los efectos de memoria de escribir (asignar) una volatilevariable.

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.

pgras
fuente
11
¿Y la respuesta más larga sería?
Julien Grenier
Convenido. Al menos necesitamos un enlace.
Julien Chastang
2
El enlace para una respuesta más larga: java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/atomic/…
Alex Siman
42

No no hay.

La potencia adicional que proporciona AtomicReference es el método compareAndSet () y sus amigos. Si no necesita esos métodos, una referencia volátil proporciona la misma semántica que AtomicReference.set () y .get ().

Avi
fuente
14

Hay varias diferencias y compensaciones:

  1. 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 .

  2. La huella de memoria se multiplica (suponiendo un entorno OOP comprimido, lo cual es cierto para la mayoría de las máquinas virtuales):

    • ref volátil = 4b
    • AtomicReference = 4b + 16b (encabezado de objeto 12b + campo de referencia 4b)
  3. 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?

  • ¿Solo necesita obtener / configurar? Quédese con un campo volátil, la solución más simple y la sobrecarga más baja.
  • ¿Necesitas la funcionalidad extra? Si se trata de una parte sensible del rendimiento (velocidad / sobrecarga de memoria) de su código, elija entre 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.
Nitsan Wakart
fuente
7

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.

sin fin
fuente
13
"El código fuente JDK es una de las mejores formas de responder a confusiones como esta" => No estoy necesariamente de acuerdo: el javadoc (que es el contrato de la clase) es la mejor manera. Lo que encuentra en el código responde la pregunta para una implementación específica, pero el código puede cambiar.
Assylias
44
Por ejemplo, esta variable en hashmap era volátil en JDK 6 pero ya no lo es en Java 7. ¿Ha basado su código en el hecho de que la variable era volátil? Se habría roto al actualizar su JDK ... Es cierto que el ejemplo es diferente pero entiendes el punto.
Assylias
¿Es CAS alguna abreviatura estándar?
abbas
1
Compare and Swap =)
sin fin el
4

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 .

Peter Lawrey
fuente
Entonces, la diferencia está en su desempeño. Si no hubiera diferencia, nunca sugeriría usar uno sobre el otro.
BT
El rendimiento es muy parecido. Una referencia atómica agrega complejidad y uso de memoria.
Peter Lawrey
@BT Un volatilecampo se puede usar como cualquier campo normal, mientras que para acceder al valor en un se AtomicReferencerequiere revisar gety setmétodos.
David Harkness
0

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".

nme
fuente