
¿Qué es un singleton en Java?
Singleton es uno de los patrones de diseño de nivel de clase más simples. A veces, la gente dice "esta clase es singleton", lo que significa que la clase implementa el patrón de diseño singleton. A veces, es necesario escribir una clase en la que restringimos la creación de instancias a un solo objeto. Por ejemplo, una clase responsable de iniciar sesión o conectarse a un base de datos. El patrón de diseño singleton describe cómo podemos lograr esto. Un singleton es un patrón de diseño que hace dos cosas:-
Garantiza que solo habrá una instancia de la clase.
-
Proporciona un único punto de acceso global a esa instancia.
-
Un constructor privado. Esto limita la capacidad de crear objetos de la clase fuera de la clase misma.
-
Un método estático público que devuelve la instancia de la clase. Este método se llama getInstance . Este es el punto de acceso global a la instancia de la clase.
Opciones de implementación
El patrón de diseño singleton se aplica de varias formas. Cada opción es buena y mala a su manera. Como siempre, no hay una opción perfecta aquí, pero debemos esforzarnos por encontrar una. En primer lugar, decidamos qué constituye bueno y malo, y qué métricas afectan la forma en que evaluamos las diversas implementaciones del patrón de diseño. Empecemos por lo bueno. Estos son los factores que hacen que una implementación sea más jugosa y atractiva:-
Inicialización diferida: la instancia no se crea hasta que se necesita.
-
Código simple y transparente: esta métrica, por supuesto, es subjetiva, pero es importante.
-
Seguridad de subprocesos: correcto funcionamiento en un entorno multiproceso.
-
Alto rendimiento en un entorno de subprocesos múltiples: poco o ningún bloqueo de subprocesos al compartir un recurso.
-
Sin inicialización perezosa: cuando la clase se carga cuando se inicia la aplicación, independientemente de si se necesita o no (paradójicamente, en el mundo de TI es mejor ser perezoso)
-
Código complejo y difícil de leer. Esta métrica también es subjetiva. Si sus ojos comienzan a sangrar, asumiremos que la implementación no es la mejor.
-
Falta de seguridad del hilo. En otras palabras, "peligro de hilo". Funcionamiento incorrecto en un entorno de subprocesos múltiples.
-
Rendimiento deficiente en un entorno de subprocesos múltiples: los subprocesos se bloquean entre sí todo el tiempo o con frecuencia al compartir un recurso.
Código
Ahora estamos listos para considerar varias opciones de implementación e indicar los pros y los contras:Simple
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return INSTANCE;
}
}
La implementación más simple. Ventajas:
-
Código simple y transparente
-
seguridad del hilo
-
Alto rendimiento en un entorno de subprocesos múltiples
- Sin inicialización perezosa.
Inicialización perezosa
public class Singleton {
private static final Singleton INSTANCE;
private Singleton() {}
public static Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
Ventajas:
-
Inicialización perezosa.
-
No es seguro para subprocesos
Acceso sincronizado
public class Singleton {
private static final Singleton INSTANCE;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
Ventajas:
-
Inicialización perezosa.
-
seguridad del hilo
-
Pobre rendimiento multiproceso
Bloqueo de doble control
public class Singleton {
private static final Singleton INSTANCE;
private Singleton() {
}
public static Singleton getInstance() {
if (INSTANCE == null) {
synchronized (Singleton.class) {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
Ventajas:
-
Inicialización perezosa.
-
seguridad del hilo
-
Alto rendimiento en un entorno de subprocesos múltiples
-
No se admite en versiones anteriores de Java inferiores a 1.5 (el uso de la palabra clave volatile es fijo desde la versión 1.5)
Titular de la clase
public class Singleton {
private Singleton() {
}
private static class SingletonHolder {
public static final Singleton HOLDER_INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.HOLDER_INSTANCE;
}
}
Ventajas:
-
Inicialización perezosa.
-
Seguridad del hilo.
-
Alto rendimiento en un entorno de subprocesos múltiples.
-
El funcionamiento correcto requiere una garantía de que el objeto singleton se inicializa sin errores. De lo contrario, la primera llamada al método getInstance generará un ExceptionInInitializerError y todas las llamadas posteriores generarán un NoClassDefFoundError .
Implementación | Inicialización perezosa | seguridad del hilo | Rendimiento multiproceso | ¿Cuándo usar? |
---|---|---|---|---|
Simple | - | + | Rápido | Nunca. O posiblemente cuando la inicialización diferida no es importante. Pero nunca sería mejor. |
Inicialización perezosa | + | - | No aplica | Siempre que no se necesite subprocesamiento múltiple |
Acceso sincronizado | + | + | Lento | Nunca. O posiblemente cuando el rendimiento multiproceso no importa. Pero nunca sería mejor. |
Bloqueo de doble control | + | + | Rápido | En casos excepcionales, cuando necesita manejar excepciones al crear el singleton (cuando el singleton del titular de la clase no es aplicable) |
Titular de la clase | + | + | Rápido | Siempre que se necesiten subprocesos múltiples y haya garantía de que el objeto singleton se creará sin problemas. |
Pros y contras del patrón singleton
En general, un singleton hace exactamente lo que se espera de él:-
Garantiza que solo habrá una instancia de la clase.
-
Proporciona un único punto de acceso global a esa instancia.
-
Un singleton viola el principio de responsabilidad única: además de sus funciones directas, la clase singleton también controla el número de instancias.
-
La dependencia de una clase ordinaria de un singleton no es visible en el contrato público de la clase.
-
Las variables globales son malas. En última instancia, un singleton se convierte en una variable global considerable.
-
La presencia de un singleton reduce la capacidad de prueba de la aplicación en su conjunto y de las clases que utilizan el singleton en particular.
GO TO FULL VERSION