2012-04-27 11 views
8

tengo una clase:¿Está volviendo una referencia del método estático thread-safe?

class PrintStringDataBuilder 
{ 
    PrintStringDataBuilder() { } 
    public static GetInstance() 
    { 
     return new PrintStringDataBuilder(); 
    } 

    //other class methods and fields, properties 
} 

accederse desde el código del cliente como:

PrintStringDataBuilder instance = PrintStringDataBuilder.GetInstance(); 

está por encima de la llamada flujos seguros?

Editar: Sólo trato de evitar escribir PrintStringDataBuilder builder = new PrintStringDataBuilder(); varias veces en la aplicación web asp.net mvc. No hay otros métodos estáticos, campos estáticos o propiedades estáticas en la clase PrintStringDataBuilder.

+0

Eso realmente depende de lo que 'nuevo PrintStringDataBuilder()' haga. ¿Estás tratando de convertirlo en un Singleton? Si es así, esto no está haciendo eso. Si no, ¿por qué tienes un método estático 'GetInstance()' cuando puedes simplemente llamar al constructor? – cadrell0

+0

¿Tiene un constructor privado 'PrintStringDataBuilder' ¿Cómo se inicializan otros campos? –

+0

¿Por qué votar abajo? Creo que es una buena pregunta – n8wrl

Respuesta

11

Sí? Sin conocer las partes internas del constructor de esa clase, se podría decir que llamar al GetInstance() era seguro para subprocesos. Sin embargo, no se garantizará que ningún método en esa instancia sea seguro para subprocesos, particularmente dado que no presentó ninguno de esos métodos.

Esto simplemente se conoce como el patrón de fábrica.

EDIT: Si usted está tratando de devolver un producto único, puede hacerlo de esta manera:

.NET 4+

private static Lazy<PrintStringDataBuilder> _instance = new Lazy<PrintStringDataBuilder>(() => 
    { 
     return new PrintStringDataBuilder(); 
    }); 

public static PrintStringDataBuilder GetInstance() 
{ 
    return _instance.Value; 
} 

.NET 3.5 y por debajo

private static PrintStringDataBuilder _instance = null; 
private static object _lockObject = new object(); 

public static PrintStringDataBuilder GetInstance() 
{ 
    if(_instance == null) 
    { 
     lock(_lockObject) 
     { 
       if(_instance == null) 
       _instance = new PrintStringDataBuilder(); 
     } 
    } 

    return _instance; 
} 
+0

Lo siento, se olvidó de escribir el constructor. Actualicé el código. – mxasim

+0

Sí, el constructor es seguro para hilos (no hace nada). ¿Estás tratando de devolver un singleton? – Tejs

+0

No, solo trato de evitar escribir PrintStringDataBuilder builder = new PrintStringDataBuilder(); varias veces – mxasim

5

Por 'threadsafe' ¿le preocupa que varios hilos que llamen a su método estático obtengan el MISMO PrintStringDataBuilder? La respuesta a eso es NO, y la llamada es segura para subprocesos.

Habiendo dicho eso, nadie puede decir por el pequeño fragmento que da si el resto de la clase es, o su constructor. Hay muchas razones por las que las instancias de clase no son seguras para subprocesos. si se refieren a propiedades estáticas sin bloqueo es un ejemplo.

3

La introducción de un método siempre es segura para subprocesos. El acceso a datos compartidos podría no serlo. Por lo tanto, este código es seguro para subprocesos porque no hay datos compartidos.

Si su intención aquí es tener una sola instancia de PrintStringDataBuilder para todos los hilos, entonces para ese propósito su código no funcionará. Necesitas el singleton adecuado. En .NET 4 el código puede ser muy compacto:

private static Lazy<PrintStringDataBuilder> instance = new Lazy<PrintStringDataBuilder>(); 

public static PrintStringDataBuilder Instance 
{ 
    get { return instance.Value; } 
} 

Esto garantizará que en cada hilo PrintStringDataBuilder.Instance apuntará a la misma y sólo una instancia del objeto PrintStringDataBuilder que se crea de una manera perezosa es decir, sólo cuando se usa por primera vez y no antes.

1

@Tejs,

En realidad, en .NET no es necesario utilizar el mecanismo de cierre de doble comprobación - hay mejores maneras alrededor de él. Pero si elige hacerlo, su implementación del bloqueo de doble verificación es incorrecta y no es realmente segura para subprocesos. El compilador puede optimizar la distancia de la inicialización de la _instance = new PrintStringDataBuilder(); - hay 3 posibles modificaciones para que su ejemplo verdaderamente seguro para subprocesos:

  1. inicializar el miembro estático en línea - sin duda el más fácil!
private static PrintStringDataBuilder _instance = new PrintStringDataBuilder; 
    public static PrintStringDataBuilder GetInstance() 
    { 
     return _instance; 
    } 

2. utilice la palabra clave 'volátil' para asegurarse de que el JIT no optimice la inicialización del PrintStringDataBuilder.


private static volatile PrintStringDataBuilder _instance = null; 
private static object _lockObject = new object(); 

public static PrintStringDataBuilder GetInstance() 
{ 
    if(_instance == null) 
    { 
     lock(_lockObject) 
     { 
       if(_instance == null) 
       { 
       _instance = new PrintStringDataBuilder(); 
       } 
     } 
    } 

    return _instance; 
}

3. Use Interlocked.Exchange con doble control de bloqueo:


private static PrintStringDataBuilder _instance = null; 
private static object _lockObject = new object(); 

public static PrintStringDataBuilder GetInstance() 
{ 
    if(_instance == null) 
    { 
     lock(_lockObject) 
     { 
       if(_instance == null) 
       { 
       var temp = new PrintStringDataBuilder(); 
       Interlocked.Exchange(ref _instance, temp); 
       } 
     } 
    } 

    return _instance; 
}

Espero que esto ayude.

Cuestiones relacionadas