2015-05-08 12 views
17

में थ्रेड सुरक्षा क्या यह String कक्षा का उपयोग कर निम्न विधियों की तरह स्थानीय चर से स्ट्रिंग बनाने के लिए सुरक्षित है? मान लीजिए कि नीचे दिए गए तरीकों को कई धागे से बुलाया जाता है।स्ट्रिंग क्लास

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

या मुझे थ्रेड सुरक्षा सुनिश्चित करने के लिए StringBuilder का उपयोग करने की आवश्यकता है?

उत्तर

19

यह बिल्कुल ठीक है। स्ट्रिंग अक्षर के अलावा कोड के किसी भी हिस्से में कोई साझा स्थिति नहीं है। चूंकि तार अपरिवर्तनीय हैं, तारों के बीच तारों को स्वतंत्र रूप से साझा करने के लिए ठीक है, और string.Format और string.Concat (स्पष्ट रूप से कोड के दूसरे भाग में बुलाया जाता है) थ्रेड-सुरक्षित हैं।

भले ही पैरामीटर में से कोई एक परिवर्तनीय था और भले ही विधि पैरामीटर को म्यूट कर दे, उदाहरण के लिए

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

... तो विधि ही अभी भी धागा सुरक्षित, जब तक कि एक से अधिक थ्रेड एक ही List<string> का उल्लेख नहीं किया होगा। यदि एक से अधिक थ्रेड किया ही List<string> को देखें तो यह असुरक्षित हो जाएगा, भले ही यह सिर्फ सूची से पढ़ा है, एक और धागा के रूप में यह परिवर्तनशील हो सकता है।

17

दोनों int और string इस विधि में पैरामीटर के रूप में प्रभावी रूप से अपरिवर्तनीय हैं और बाहर कोड से नहीं बदला जा सकता।

इसलिए इस मामले में Format विधि याके साथ थ्रेड-सुरक्षा की परवाह करने की आवश्यकता नहीं है।


लेकिन हमें लगता है कि हम कुछ वर्ग MyObject कि परिवर्तनशील है और बाहर से बदला जा सकता है डालते हैं:

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

इस मामले में पहले दृष्टिकोण के साथ या दूसरी है कि क्या आप असंगत मूल्य लौट सकते हैं (यह एक मान पहले से ही आउटपुट में डाल दिए जाने के बाद वैल्यू 1 और वैल्यू 2 बदल दिए गए हैं।)

@JonSkeet pointed के रूप में यह असल में विधि नहीं है जो असुरक्षित है, लेकिन कक्षा अलग-अलग धागे के बीच इस तरह से साझा करने के लिए असुरक्षित है ।

इस स्थिति आप या तो विशेष धागे की सुरक्षित उदाहरण विधि बनाना पड़ेगा संभाल करने के लिए:

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

या तरीकों कि इसका इस्तेमाल में ऐसे मामलों पर कुछ अतिरिक्त लॉकिंग का उपयोग करें। पहला इन-क्लास दृष्टिकोण स्पष्ट रूप से कम त्रुटि-प्रवण है, लेकिन प्रदर्शन को कम कर सकता है और बहुत सारे बॉयलर-प्लेट कोड बना सकता है। आदर्श रूप से, समवर्ती प्रोग्रामिंग में आपको साझा परिवर्तनीय स्थिति और इसकी स्थिरता the better के बारे में परवाह करने की आवश्यकता कम होती है।

+7

मैं यह नहीं कहूंगा कि आपका बाद का मामला * विधि * थ्रेड-असुरक्षित बनाता है - यह * थ्रेड * (माइक्लास) असुरक्षित बनाता है जो एकाधिक धागे के बीच उदाहरण साझा करने के लिए असुरक्षित बनाता है, जो आईएमओ थोड़ा अलग मामला है। –

+1

आपका "थ्रेड-सुरक्षित" संस्करण वास्तव में थ्रेड-सुरक्षित नहीं है ... क्योंकि कोई अन्य थ्रेड लॉक प्राप्त किए बिना 'value1' और' value2' को संशोधित कर सकता है। –

+1

@ जोन्सकेट धन्यवाद। ताले जोड़ने के लिए भूल गए। –

5

दोनों विधियां थ्रेड-सुरक्षित हैं, क्योंकि इससे कोई फर्क नहीं पड़ता कि आप WriteResult के अंदर क्या करते हैं। जब तक यह परिवर्तनीय स्थिर स्थिति का उपयोग नहीं करता है, और इसके पैरामीटर को बाहर से नहीं बदला जा सकता है, तो आपकी स्थिर विधि थ्रेड-सुरक्षित है।

यह सत्यापित करना आसान है कि विधियां स्थिर स्थिति का उपयोग नहीं करती हैं।यह भी है कि विधि के मानकों को सत्यापित करने के लिए आसान बाहर से नहीं बदला जा सकता है:

  • value, नहीं बदला जा सकता, क्योंकि यह आदिम प्रकार की है, और यह मान द्वारा पारित कर दिया है
  • name बदला नहीं जा सकता, क्योंकि string वस्तुओं अपरिवर्तनीय हैं।
संबंधित मुद्दे