Seguridad de hilo en clases Singleton de Java

Singleton es uno de los patrones de diseño creacionales más ampliamente utilizados para restringir la creación de objetos por parte de las aplicaciones. Si lo estás utilizando en un entorno multihebra, la seguridad de hilo de la clase singleton es muy importante. En aplicaciones del mundo real, los recursos como las conexiones de base de datos o los Sistemas de Información Empresarial (EIS) son limitados y deben utilizarse sabiamente para evitar problemas de recursos. Para lograr esto, podemos implementar un patrón de diseño Singleton. Podemos crear una clase envolvente para el recurso y limitar el número de objetos creados en tiempo de ejecución a uno.

Singleton Thread Safe en Java

En general, seguimos los siguientes pasos para crear una clase singleton:

  1. Crear el constructor privado para evitar la creación de nuevos objetos con el operador new.
  2. Declarar una instancia estática privada de la misma clase.
  3. Proporcione un método público y estático que devuelva la variable de instancia de la clase singleton. Si la variable no está inicializada, inicialícela; de lo contrario, simplemente devuelva la variable de instancia.

Utilizando los pasos anteriores, he creado una clase singleton que se ve así. ASingleton.java

package com.journaldev.designpatterns;

public class ASingleton {

	private static ASingleton instance = null;

	private ASingleton() {
	}

	public static ASingleton getInstance() {
		if (instance == null) {
			instance = new ASingleton();
		}
		return instance;
	}

}

En el código anterior, el método getInstance() no es seguro para subprocesos. Múltiples subprocesos pueden acceder a él al mismo tiempo. Para los primeros pocos subprocesos cuando la variable de instancia no está inicializada, múltiples subprocesos pueden entrar en el bucle if y crear múltiples instancias. Esto romperá nuestra implementación de singleton.

¿Cómo lograr la seguridad en subprocesos en la clase Singleton?

Existen tres formas mediante las cuales podemos lograr la seguridad en subprocesos.

  1. Crear la variable de instancia en el momento de la carga de la clase.
    Pros:
  • Seguridad en subprocesos sin sincronización
  • Fácil de implementar

Contras:

  • Creación temprana de recursos que podrían no ser utilizados en la aplicación.
  • La aplicación cliente no puede pasar ningún argumento, por lo que no podemos reutilizarlo. Por ejemplo, tener una clase singleton genérica para la conexión a la base de datos donde la aplicación cliente suministra las propiedades del servidor de base de datos.
  1. Sincronizar el método getInstance().
    Pros:
  • La seguridad de subprocesos está garantizada.
  • La aplicación cliente puede pasar parámetros
  • Se logra la inicialización perezosa

Contras:

  • Rendimiento lento debido al sobrecosto de bloqueo.
  • Sincronización innecesaria que no es requerida una vez que la variable de instancia está inicializada.
  1. Usar bloque sincronizado dentro del bucle if y variable volátil
    Pros:
  • La seguridad de subprocesos está garantizada
  • La aplicación cliente puede pasar argumentos
  • Se logra la inicialización perezosa
  • El costo de sincronización es mínimo y solo se aplica para los primeros pocos subprocesos cuando la variable es nula.

Contras:

  • Condición adicional

Al observar las tres formas de lograr la seguridad de subprocesos, creo que la tercera opción es la mejor. En ese caso, la clase modificada se verá así:

package com.journaldev.designpatterns;

public class ASingleton {

	private static volatile ASingleton instance;
	private static Object mutex = new Object();

	private ASingleton() {
	}

	public static ASingleton getInstance() {
		ASingleton result = instance;
		if (result == null) {
			synchronized (mutex) {
				result = instance;
				if (result == null)
					instance = result = new ASingleton();
			}
		}
		return result;
	}

}

La variable local resultado parece innecesaria. Pero está allí para mejorar el rendimiento de nuestro código. En casos donde la instancia ya está inicializada (la mayoría del tiempo), el campo volátil solo se accede una vez (debido a “return result;” en lugar de “return instance;”). Esto puede mejorar el rendimiento general del método hasta en un 25 por ciento. Si crees que hay mejores formas de lograr esto o si la seguridad de subprocesos está comprometida en la implementación anterior, por favor comenta y compártelo con todos nosotros.

Consejo de bonificación

String no es una opción muy buena para ser utilizada con la palabra clave synchronized. Esto se debe a que se almacenan en un conjunto de cadenas y no queremos bloquear una cadena que podría estar siendo utilizada por otro fragmento de código. Por lo tanto, estoy utilizando una variable de tipo Object. Obtenga más información sobre la sincronización y la seguridad de hilos en Java.

Puedes consultar más ejemplos de Java en nuestro Repositorio de GitHub.

Source:
https://www.digitalocean.com/community/tutorials/thread-safety-in-java-singleton-classes