2015-05-08 26 views
17

Aşağıdaki yöntemlerde olduğu gibi String sınıfını kullanarak yerel değişkenlerden dizeleri oluşturmak için iş parçacığı güvenli midir? Aşağıdaki yöntemlerin birkaç ileti dizisinden çağrıldığını varsayalım.Dize sınıfında iplik güvenliği

public static string WriteResult(int value, string name) 
{ 
    return string.Format("Result: value={0} name={1}", value, name); 
} 

public static string WriteResult2(int value, string name) 
{ 
    return "Result: value=" + value + " name=" + name; 
} 

Ya iplik güvenliğini sağlamak için StringBuilder kullanmak gerekiyor? Bu yöntemde parametre olarak

cevap

19

Bu kesinlikle sorun değil. Dize değişmezlerinden başka herhangi bir kod parçasında paylaşılan bir durum yoktur. Dizeler değişmez olduğundan, dizeler arasında serbestçe paylaşılacak dizeler için iyi ve hem string.Format hem de string.Concat (ikinci kod parçasında örtülü olarak adlandırılır) iş parçacığı için güvenlidir. Parametrelerden biri değiştirilebilseydi ve metot parametrelerde mutasyona uğratsa bile, örn.

public static void AddResult(int value, List<string> results) 
{ 
    results.Add("Value " + value); 
} 

... sonra yöntem kendisi hala iş parçacığı güvenli olacaktır sürece birden parçacığı aynı List<string> bakın vermedi. yaptığı birden parçacığı aynı List<string> başvurursanız o zaman başka bir iş parçacığı bunu mutasyona olabilir olarak sadece listeden okumak bile güvensiz olurdu.

17
Hem int

ve string etkili bir iletmenin ve dış kod tarafından değiştirilemez.

Bu durumda, Format yöntemiyle veya String.Concat ile iş parçacığı güvenliği ile ilgilenmeye gerek yoktur.


Ama bize değişebilirdir ve dışarıdan değiştirilebilir bazı sınıf MyObject olduğunu varsayalım: (

public class MyClass 
{ 
    public Int32 value1 { get; set; } 
    public String value2 { get; set;} 
} 

public static string WriteResult2(MyObject obj) 
{ 
    return "Result: value=" + obj.value1 + " name=" + obj.value2 ; 
} 

Bu durumda tutarsız değer döndürebilir ilk yaklaşımla veya ikinci olsun onu her ikisi de değer1 ve değer2, bir değer zaten çıkışa konulduktan sonra değiştirilir.)

As @JonSkeet pointed aslında, güvensiz olan yöntemin kendisi değildir, ancak sınıfın kendisi farklı konular arasında paylaşılacak güvensizdir. .

özel evreli örnek yöntemini oluşturmak sahip olacaktır Bu durumu düzeltmek için:

public class MyClass 
{ 
    private Object lockObj = new Object(); 
    public Int32 value1 
    { 
     get 
     { 
      lock (this.lockObj) { ... }); 
     } 
     set 
     { 
      lock (this.lockObj) { ... }); 
     } 
    } 
    public String value2 
    { 
     get 
     { 
      lock (this.lockObj) { ... }); 
     } 
     set 
     { 
      lock (this.lockObj) { ... }); 
     } 
    } 

    public string WriteResult2() 
    { 
     lock (this.lockObj) 
     { 
      return "Result: value=" + this.value1 + " name=" + this.value2 ; 
     } 
    } 
} 

Veya kullanmak yöntemlerde gibi durumlarda aşırı bazı ek kilitleme kullanın. Sınıftaki ilk yaklaşım açıkça daha az hataya açık, ancak performansı azaltabilir ve çok sayıda kazan-plaka kodu oluşturabilir. İdeal olarak, eşzamanlı programlamada, paylaşılan değişebilir durum ve onun tutarlılığıyla ilgili daha az dikkat etmeniz gerekir the better.

+7

Ben senin ikinci vaka * yöntemini yapar söyleyemem * parçacığı güvensiz - bu IMO biraz daha farklı bir konudur çoklu iş parçacığı arasındaki * tipi * (Sınıfım) paylaşmak için güvensiz örneklerini yapar. –

+1

"İş parçacığı güvenli" sürümünüz aslında iş parçacığı için güvenli değil ... çünkü herhangi bir iş parçacığı, bir değer edinmeden "değer1" ve "değer2" değiştirebilir. –

+1

@JonSkeet Teşekkürler. Kilit eklemeyi unuttum. –

5

Her iki yöntem de iş parçacığı için güvenlidir, çünkü WriteResult içinde ne yaptığınız önemli değildir. Değişken durağan durum kullanılmadığı ve parametrelerinin dışardan değiştirilemediği sürece, statik yönteminiz diş güvenlidir.

Yöntemlerin statik durum kullanmadığını doğrulamak kolaydır.Aynı zamanda dışarıdan değiştirilemez o yöntemin parametrelerinden doğrulamak kolaydır:

  • value ilkel tiptedir, çünkü değiştirilemez ve string nesneler, çünkü
  • name değiştirilemez değeriyle geçirilir değişmezdir.