Si, es necesario. Hay varios métodos que puede utilizar para lograr la seguridad de los subprocesos con la inicialización diferida:
Sincronización draconiana:
private static YourObject instance;
public static synchronized YourObject getInstance() {
if (instance == null) {
instance = new YourObject();
}
return instance;
}
Esta solución requiere que todos los subprocesos estén sincronizados cuando en realidad solo deben estar los primeros.
Verifique la sincronización :
private static final Object lock = new Object();
private static volatile YourObject instance;
public static YourObject getInstance() {
YourObject r = instance;
if (r == null) {
synchronized (lock) { // While we were waiting for the lock, another
r = instance; // thread may have instantiated the object.
if (r == null) {
r = new YourObject();
instance = r;
}
}
}
return r;
}
Esta solución asegura que solo los primeros hilos que intentan adquirir su singleton tengan que pasar por el proceso de adquisición del candado.
Inicialización a pedido :
private static class InstanceHolder {
private static final YourObject instance = new YourObject();
}
public static YourObject getInstance() {
return InstanceHolder.instance;
}
Esta solución aprovecha las garantías del modelo de memoria de Java sobre la inicialización de clases para garantizar la seguridad de los subprocesos. Cada clase solo se puede cargar una vez y solo se cargará cuando sea necesario. Eso significa que la primera vez que getInstance
se llama, InstanceHolder
se cargará y instance
se creará, y dado que esto está controlado por ClassLoader
s, no es necesaria ninguna sincronización adicional.
Draconian synchronization
yDouble check synchronization
getInstance () - ¡el método debe ser estático!static
, pero podría tener más sentido si lo fueran. Enmendado según lo solicitado.r
no es necesario para la corrección. Es solo una optimización para evitar acceder al campo volátil, ya que eso es mucho más caro que acceder a una variable local.¡Este patrón realiza una inicialización diferida segura para subprocesos de la instancia sin sincronización explícita!
Funciona porque usa el cargador de clases para hacer toda la sincronización por usted de forma gratuita:
MySingleton.Loader
primero se accede a la clase dentro delgetInstance()
método, por lo que laLoader
clase se carga cuandogetInstance()
se llama por primera vez. Además, el cargador de clases garantiza que toda la inicialización estática esté completa antes de que tenga acceso a la clase; eso es lo que le brinda seguridad para los subprocesos.Es como magia.
En realidad, es muy similar al patrón de enumeración de Jhurtado, pero encuentro que el patrón de enumeración es un abuso del concepto de enumeración (aunque funciona)
fuente
final
debería agregarse. Hecho.Si está trabajando en un entorno multiproceso en Java y necesita garantizar que todos esos subprocesos acceden a una sola instancia de una clase, puede usar un Enum. Esto tendrá la ventaja adicional de ayudarlo a manejar la serialización.
y luego haga que sus hilos usen su instancia como:
fuente
Sí, necesitas
getInstance()
sincronizar. Si no es así, podría surgir una situación en la que se puedan crear varias instancias de la clase.Considere el caso en el que tiene dos subprocesos que llaman
getInstance()
al mismo tiempo. Ahora imagine que T1 se ejecuta justo después de lainstance == null
comprobación y luego T2 se ejecuta. En este momento, la instancia no se crea o configura, por lo que T2 pasará la verificación y creará la instancia. Ahora imagine que la ejecución vuelve a cambiar a T1. Ahora se crea el singleton, ¡pero T1 ya ha hecho la verificación! ¡Procederá a hacer el objeto nuevamente! HacergetInstance()
sincronizados evita este problema.Hay algunas formas de hacer que los singleton sean seguros para subprocesos, pero
getInstance()
sincronizarlos es probablemente la más simple.fuente
Enum singleton
La forma más sencilla de implementar un Singleton que sea seguro para subprocesos es usar un Enum
Este código funciona desde la introducción de Enum en Java 1.5
Bloqueo doble comprobado
Si desea codificar un singleton "clásico" que funcione en un entorno multiproceso (a partir de Java 1.5), debe usar este.
Esto no es seguro para subprocesos antes de la 1.5 porque la implementación de la palabra clave volátil era diferente.
Carga temprana de Singleton (funciona incluso antes de Java 1.5)
Esta implementación crea una instancia del singleton cuando se carga la clase y proporciona seguridad para los subprocesos.
fuente
También puede usar un bloque de código estático para crear una instancia de la instancia en la carga de la clase y evitar los problemas de sincronización de subprocesos.
fuente
instance
final 2. Debería hacergetInstance()
estático.Consulte esta publicación para conocer la mejor manera de implementar Singleton.
¿Cuál es una forma eficiente de implementar un patrón singleton en Java?
Depende de la forma en que haya implementado el método. Si usa doble bloqueo sin variable volátil, puede obtener un objeto Singleton parcialmente construido.
Consulte esta pregunta para obtener más detalles:
¿Por qué se usa volátil en este ejemplo de bloqueo doble verificado?
No es necesario si implementa el Singleton de las siguientes formas
Consulte esta pregunta para obtener más detalles.
Patrón de diseño Java Singleton: Preguntas
fuente
Fuente: Effective Java -> Item 2
Sugiere usarlo, si está seguro de que la clase siempre permanecerá singleton.
fuente