2010-06-02 24 views
8

Se me ocurre esta pregunta al implementar el patrón de singleton en Java. Aunque el ejemplo que figura a continuación no es mi código real, es muy similar al original.Cómo sincronizar el método estático en java

public class ConnectionFactory{ 
    private static ConnectionFactory instance; 

    public static synchronized ConnectionFactory getInstance(){ 
     if(instance == null){ 
      instance = new ConnectionFactory(); 
     } 

     return instance; 
    } 

    private ConnectionFactory(){ 
     // private constructor implementation 
    } 
} 

Porque no estoy muy seguro sobre el comportamiento de un método sincronizado estático, que conseguir una cierta sugerencia de Google - no tienen (o lo menos posible) múltiples métodos sincronizados estáticas en la misma clase. Supongo que cuando se implementa el método sincronizado estático, un bloqueo pertenece al objeto Class, de forma que múltiples métodos sincronizados pueden degradar el rendimiento del sistema.

¿Estoy en lo cierto? o JVM utiliza otro mecanismo para implementar el método estático sincronizado? ¿Cuál es la mejor práctica si tengo que implementar múltiples métodos sincronizados estáticos en una clase?

¡Gracias a todos!

Saludos cordiales!

+2

es su código real también preocupados por la inicialización perezosa? Porque eso suele ser un desperdicio de código y tiempo de desarrollador; Inicializar el campo en su declaración es lo correcto para hacer el 99% del tiempo y hace que la sincronización sea innecesaria. –

Respuesta

7

El mejor enfoque (que hace el menor número de cambios en el código como sea posible) es hacerlo de esta manera:

public class ConnectionFactory{ 
    private static ConnectionFactory instance = new ConnectionFactory(); 

    public static ConnectionFactory getInstance(){ 
     return instance; 
    } 

    private ConnectionFactory(){ 
    } 
} 

Como se puede ver, no hay una necesidad real en getInstance método ahora, para que puedas simplificar el código para:

public class ConnectionFactory{ 
    public static final ConnectionFactory INSTANCE = new ConnectionFactory(); 

    private ConnectionFactory(){ 
    } 
} 

UPD sobre la sincronización: la mejor manera se sincronizan en una cerradura que no es visible para las clases de exteriores, es decir:

public class ConnectionFactory{ 
    private static final Object lock = new Object(); 

    public static void doSmth() { 
     synchronized (lock) { 

      ... 
     } 
    } 

    public static void doSmthElse() { 
     synchronized (lock) { 

      ... 
     } 
    } 
} 

Hay muchas discusiones sobre "por qué es mala idea sincronizar en this" (como this one), creo que lo mismo es real para sincronizar en clase.

+0

¿cómo crearía la 'instancia', si el único constructor lanza una excepción? – unbeli

+0

@unbeli: fue mi mal, corregido. Pero si ni siquiera necesita una instancia, si fue una solución correcta. – Roman

+0

@unbeli: utilizando un método de fábrica estático privado o un bloque de inicializador estático. Desafortunadamente, todas esas discusiones sobre el modelo de memoria Java y el bloqueo comprobado han contaminado Internet con cientos de ejemplos de código que ahora dan a los principiantes la impresión de que la inicialización lenta de singleton en el método getInstance() realmente es una buena idea o incluso la norma. –

2

Sí, los métodos estáticos están sincronizados en su objeto de clase. No me preocuparía por el rendimiento aquí, ya que probablemente este no sea su punto caliente de rendimiento. Hazlo simple, optimiza cuándo y dónde lo necesites.

2

Los métodos estáticos sincronizados utilizan el bloqueo de la clase. En el caso de su ejemplo, accedería al bloqueo en el objeto de clase ConnectionFactory. La mejor práctica es no aferrarse a las cerraduras por más tiempo de lo necesario. Si tiene múltiples métodos sincronizados no es un problema en sí mismo.

3

Hay varias formas de crear un singleton.

Una manera recomendada es utilizar una enumeración (garantizado para crear solo un ejemplo):

public enum ConnectionFactory { 

    INSTANCE; 

} 

o puede crear estáticamente cuando se carga la clase:

public class ConnectionFactory { 

    private static ConnectionFactory INSTANCE = new ConnectionFactory(); 

    private ConnectionFactory() {} 

    public static ConnectionFactory getInstance() { 
    return INSTANCE; 
    }  

} 

Si necesitan perezosamente cargarlo puede utilizar este idioma (en lugar de la double checked locking anti-pattern)

public class ConnectionFactory { 

    private static class ConnectionFactoryHolder { 
    private static ConnectionFactory INSTANCE = new ConnectionFactory(); 
    } 

    public static ConnectionFactory getInstance() { 
    return ConnectionFactoryHolder.INSTANCE; 
    } 

} 
0

Efectivo Java recomienda usar Enums para crear singleton.Por lo que el código sería algo como esto:

public enum ConnectionFactory{ 
INSTANCE; 

// Other factory methods go here. 

} 

}

Cuestiones relacionadas