2012-04-27 16 views
8

Mam klasy:Powraca odwołanie metody statycznej wątku bezpieczne?

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

    //other class methods and fields, properties 
} 

Dostęp z Kodeksem klienta jak:

PrintStringDataBuilder instance = PrintStringDataBuilder.GetInstance(); 

jest powyżej połączenia wątku bezpieczny?

Edytuj: Po prostu próbuję uniknąć pisania PrintStringDataBuilder builder = new PrintStringDataBuilder(); wiele razy w aplikacji webowej asp.net mvc. Nie ma innych metod statycznych, pól statycznych ani właściwości statycznych w klasie PrintStringDataBuilder.

+0

To naprawdę zależy od tego, co robi 'nowy PrintStringDataBuilder()'. Próbujesz zrobić z tego Singleton? Jeśli tak, to tego nie robi. Jeśli nie, to dlaczego masz statyczną metodę 'GetInstance()', gdy możesz po prostu wywołać konstruktora. – cadrell0

+0

Czy masz prywatnego konstruktora 'PrintStringDataBuilder' Jak są inicjowane inne pola? –

+0

Dlaczego głosowanie w dół? Myślę, że to dobre pytanie. – n8wrl

Odpowiedz

11

Tak? Nie znając wewnętrznych cech konstruktora tej klasy, można powiedzieć, że wywołanie GetInstance() było bezpieczne dla wątków. Żadne metody na tej instancji nie gwarantują bezpieczeństwa wątku, szczególnie, że nie przedstawiłeś żadnej z tych metod.

To jest po prostu znane jako wzór fabryczny.

EDIT: Jeśli chcesz, aby powrócić pojedyncza, można to zrobić tak:

NET 4+

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

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

.NET 3.5 i poniżej

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

Przepraszam, zapomniałem napisać konstruktora. Zaktualizowałem kod. – mxasim

+0

Tak, konstruktor jest bezpieczny dla wątków (nie robi nic). Próbujesz zwrócić singleton? – Tejs

+0

Nie, po prostu próbuję uniknąć pisania Builder PrintStringDataBuilder = new PrintStringDataBuilder(); wiele razy – mxasim

5

By "wątki bezpieczne" czy martwisz się, że wiele wątków wywołujących twoją statyczną metodę otrzyma SAME PrintStringDataBuilder? Odpowiedzią na to jest NIE, a połączenie jest bezpieczne dla wątków.

Powiedziawszy to, nikt nie może powiedzieć z małego fragmentu, który podajesz, czy reszta klasy jest, czy też jej konstruktorem. Istnieje wiele powodów, dla których instancje klasy nie są wątkowane. jeśli odnoszą się do właściwości statycznych bez blokowania, to przykład.

3

Wprowadzanie metody jest zawsze bezpieczne dla wątków. Dostęp do udostępnionych danych może być inny. Ten kod jest bezpieczny dla wątków, ponieważ nie ma udostępnionych danych.

Jeśli Twoim zamiarem jest posiadanie pojedynczej instancji PrintStringDataBuilder dla wszystkich wątków, to w tym celu Twój kod nie będzie działał. Potrzebujesz właściwego singletonu. W .NET 4 kod może być bardzo zwarty:

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

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

To zagwarantuje, że w każdym wątku PrintStringDataBuilder.Instance będzie wskazywać na ten sam i tylko jeden przykład swojego obiektu PrintStringDataBuilder który zostanie utworzony w leniwe sposób czyli tylko wtedy, gdy to jest po raz pierwszy użyte i nie wcześniej.

1

@Tejs,

Właściwie w .NET nie trzeba używać mechanizmu zamka podwójnego wyboru - istnieją lepsze sposoby wokół niego. Ale jeśli zdecydujesz się na to, twoja implementacja blokady podwójnego sprawdzenia jest nieprawidłowa i nie jest prawdziwie bezpieczna dla wątków. Kompilator mógł zoptymalizować dala inicjalizacji _instance = new PrintStringDataBuilder(); - są 3 możliwe modyfikacje, aby Państwa przykładem prawdziwie bezpieczne wątek:

  1. zainicjować statycznych inline - Zdecydowanie najłatwiej!
private static PrintStringDataBuilder _instance = new PrintStringDataBuilder; 
    public static PrintStringDataBuilder GetInstance() 
    { 
     return _instance; 
    } 

2. użyj słowa kluczowego "volatile", aby upewnić się, że inicjalizacja PrintStringDataBuilder nie została zoptymalizowana przez JIT.


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. Użyj opcji Interlocked.Exchange z blokadą z podwójną kontrolą:


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

Mam nadzieję, że to pomoże.

Powiązane problemy