Referencia volátil Java vs. AtomicReference

¿Hay alguna diferencia entre una referencia de Objeto volatile y AtomicReference en caso de que use simplemente get() y set() AtomicReference de AtomicReference ?

La respuesta corta es: No.

Del documento del paquete java.util.concurrent.atomic :

Los efectos de memoria para los accesos y las actualizaciones de atomics generalmente siguen las reglas para volátiles:

  • get tiene los efectos de memoria de leer una variable volatile .
  • set tiene los efectos de memoria de escribir (asignar) una variable volatile .

Por cierto, el documento del paquete es muy bueno y todo se explica …


lazySet (introducido en Java 6) es una nueva operación introducida que tiene una semántica inalcanzable a través de variables volatile ; vea esta publicación para más información.

No no hay.

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

El código fuente de JDK es una de las mejores formas de responder a confusiones como esta. Si observa el código en AtomicReference, usa una variable volátil para el almacenamiento de objetos.

 private volatile V value; 

Así que, obviamente, si vas a usar get () y set () en AtomicReference es como usar una variable volátil. Pero como comentaron otros lectores, AtomicReference proporciona semántica de CAS adicional. Entonces, primero decida si quiere semántica de CAS o no, y si solo usa AtomicReference.

AtomicReference proporciona una funcionalidad adicional que una variable volátil no proporciona. Como ha leído la API, sabrá esto, pero también proporciona un locking que puede ser útil para algunas operaciones.

Sin embargo, a menos que necesite esta funcionalidad adicional, le sugiero que use un campo simple volátil.

Hay varias diferencias y compensaciones:

  1. El uso de un get / set AtomicReference tiene la misma semántica de JMM que un campo volátil (como dice javadoc), pero AtomicReference es un contenedor alrededor de una referencia, por lo que cualquier acceso al campo implica una persecución de puntero adicional .

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

    • ref volátil = 4b
    • AtomicReference = 4b + 16b (cabecera del objeto 12b + campo de referencia 4b)
  3. AtomicReference ofrece una API más rica que una referencia volátil. Puede recuperar la API para la referencia volátil utilizando un AtomicFieldUpdater , o con Java 9 a VarHandle . También puede sun.misc.Unsafe directamente a sun.misc.Unsafe si le gusta correr con tijeras. AtomicReference sí mismo se implementa utilizando Unsafe .

Entonces, ¿cuándo es bueno elegir uno sobre el otro?

  • ¿Solo necesita get / set? Quédese con un campo volátil, la solución más simple y la menor sobrecarga.
  • ¿Necesita la funcionalidad adicional? Si se trata de una parte sensible del rendimiento (velocidad / sobrecarga de memoria) de su código, haga una elección entre AtomicReference / AtomicFieldUpdater / Unsafe donde tiende a pagar en legibilidad y riesgo para su ganancia de rendimiento. Si no es una zona sensible, solo tiene que ir a AtomicReference . Los escritores de bibliotecas suelen utilizar una combinación de estos métodos según los JDK específicos, las restricciones esperadas de la API, las limitaciones de memoria, etc.