2012-04-27 7 views
8

Ich habe eine Klasse:Wird eine Referenz von der statischen Methode threadsicher zurückgegeben?

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

    //other class methods and fields, properties 
} 

von Client-Code Accessed als:

PrintStringDataBuilder instance = PrintStringDataBuilder.GetInstance(); 

Ist oben Anruf Thread-sicher?

Edit: Nur versuchen, das Schreiben zu vermeiden PrintStringDataBuilder builder = new PrintStringDataBuilder(); mehrmals in asp.net mvc Web App. In der PrintStringDataBuilder-Klasse gibt es keine anderen statischen Methoden, statische Felder oder statische Eigenschaften.

+0

Das hängt wirklich davon ab, was 'new PrintStringDataBuilder()' tut. Versuchen Sie, es zu einem Singleton zu machen? Wenn das so ist, macht das das nicht. Wenn nicht, warum haben Sie eine statische 'GetInstance()' Methode, wenn Sie einfach den Konstruktor aufrufen können. – cadrell0

+0

Haben Sie einen privaten Konstruktor 'PrintStringDataBuilder' Wie werden andere Felder initialisiert? –

+0

Warum die Abstimmung runter? Ich denke, es ist eine gute Frage – n8wrl

Antwort

11

Ja? Ohne die Interna des Konstruktors dieser Klasse zu kennen, könnte man sagen, dass der Aufruf von GetInstance() threadsicher war. Es ist jedoch nicht garantiert, dass alle Methoden für diese Instanz threadsicher sind, insbesondere, weil Sie keine dieser Methoden angezeigt haben.

Dies wird einfach als Fabrikmuster bekannt.

EDIT: Wenn Sie versuchen, einen Singleton zurückkehren, können Sie es wie so tun:

.NET 4+

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

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

.NET 3.5 und unter

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

Sorry, habe vergessen, Konstruktor zu schreiben. Ich habe den Code aktualisiert. – mxasim

+0

Ja, der Konstruktor ist Thread-sicher (es tut nichts). Willst du einen Singleton zurückgeben? – Tejs

+0

Nein, ich versuche nur zu vermeiden, PrintStringDataBuilder zu schreiben. Builder = new PrintStringDataBuilder(); mehrmals – mxasim

5

von 'threadsafe' sind Sie besorgt, dass mehrere Threads, die Ihre statische Methode aufrufen, den gleichen PrintStringDataBuilder bekommen? Die Antwort darauf ist NEIN und der Anruf ist Thread-sicher.

auch sagen, dass niemand aus dem kleinen Schnipsel kann Sie sagen, der Rest der Klasse geben, ob ist, oder der Konstruktor. Es gibt viele Gründe, warum die Klasseninstanzen nicht Thread-sicher sind. Wenn sie sich auf statische Eigenschaften ohne Verriegelung beziehen, ist dies ein Beispiel.

3

ein Verfahren eintritt, wird immer sicher fädeln. Zugriff auf freigegebene Daten möglicherweise nicht. Daher ist dieser Code Thread-sicher, da keine gemeinsamen Daten vorhanden sind.

Wenn Ihre Absicht ist es, eine einzelne Instanz PrintStringDataBuilder für alle Threads Code dann hat zu diesem Zweck wird nicht funktionieren. Du brauchst einen richtigen Singleton. In .NET 4 kann der Code sehr kompakt sein:

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

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

Dies, dass in jedem Thread garantieren PrintStringDataBuilder.Instance auf die gleiche und nur eine Instanz des PrintStringDataBuilder Objekts zeigen wird, die in einem faulen Weise erstellt werden also nur dann, wenn Es wird zuerst verwendet und nicht früher.

1

@Tejs,

Eigentlich in .NET müssen Sie nicht über die doppelte Kontrolle Verriegelungsmechanismus verwenden - es gibt bessere Möglichkeiten um ihn herum. Aber wenn Sie sich dafür entscheiden, ist Ihre Implementierung der Double-Check-Sperre falsch und nicht wirklich Thread-sicher. Der Compiler kann die Initialisierung der _instance = new PrintStringDataBuilder(); optimiert entfernt - es gibt drei mögliche Modifikationen Ihr Beispiel wirklich Thread-sicher zu machen:

  1. initialisieren das statische Element Inline - definitiv die einfachste!
private static PrintStringDataBuilder _instance = new PrintStringDataBuilder; 
    public static PrintStringDataBuilder GetInstance() 
    { 
     return _instance; 
    } 

2. Verwenden Sie das Schlüsselwort 'volatile', um sicherzustellen, dass die Initialisierung des PrintStringDataBuilder nicht vom JIT optimiert wird.


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. Verwenden Sie Interlocked.Exchange mit Vier-Augen-lock:


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; 
}

Hoffnung, das hilft.

Verwandte Themen