ProgramaciónDesarrollador Backend

Explica qué es la publicación segura en Java, por qué es necesaria en la programación concurrente y qué formas hay de garantizarla.

Supere entrevistas con el asistente de IA Hintsage

Respuesta

Publicación Segura (safe publication) es la garantía de distribución segura de un objeto entre hilos: si un hilo crea e inicializa un objeto, otro hilo siempre verá el objeto completamente construido, y no su estado parcialmente inicializado.

Sin publicación segura, se puede obtener una condición de carrera: un hilo ve una parte no inicializada del objeto, incluso si el constructor ya ha terminado.

Formas de garantizar la publicación segura:

  • Usar campos final: su valor es garantizado para ser visible por otros hilos después del constructor.
  • Publicar el objeto a través de una variable volatile o AtomicReference.
  • Publicar el objeto a través de contenedores seguros para hilos (por ejemplo, colecciones de java.util.concurrent).
  • Usar synchronized al crear y leer el objeto.

Ejemplo (no seguro):

public class Holder { private int n; public Holder(int n) { this.n = n; } } Holder holder; void publish() { holder = new Holder(42); } // Seguridad no garantizada

¡Pueden verse objetos no completamente construidos!

Ejemplo (seguro):

volatile Holder holder; void publish() { holder = new Holder(42); } // La lectura de holder también será segura

Pregunta trampa

Si en el objeto todos los campos son final, ¿garantiza esto siempre la publicación segura?

Respuesta: No, solo si la referencia al nuevo objeto se publica antes de terminar el constructor. Si la referencia se comparte con otros hilos antes de que finalice el constructor, los campos pueden no estar completamente inicializados. Se debe evitar la publicación de this o referencias a objetos no completamente construidos durante la ejecución del constructor.

Ejemplo (¡peligroso!):

public class PublishEscape { public static PublishEscape instance; public PublishEscape() { instance = this; // ¡Mal! this se publica antes de terminar el constructor } }

Historia

Un desarrollador asignó una referencia a una instancia de Service a un campo accesible a través de static, antes de que el constructor terminara. Como resultado, otro hilo recibió un objeto parcialmente construido, lo que causó un comportamiento impredecible en producción.


Historia

En una aplicación web, los objetos singleton se creaban sin sincronización adicional. Bajo carga, algunos hilos obtenían null o campos incorrectamente inicializados, lo que conducía a Intermittent NullPointerException.


Historia

En una biblioteca, se utilizó una List común para el caché entre hilos; faltaba publicación segura y la inicialización no garantizaba visibilidad a nuevos hilos. Como resultado, el caché funcionaba de manera caótica, comprometiendo la integridad de los datos.