2013-06-06 4 views
9

मुझे जावा में अस्थिर चर को समझने में थोड़ा कठिनाई हो रही है।क्या अस्थिर चर के लिए सिंक्रनाइज़ पहुंच की आवश्यकता है?

public class MyClass<T> { 

    private volatile T lastValue; 

    // ... other code ... 

} 

मैं सहित lastValue के खिलाफ कुछ बुनियादी आपरेशन लागू करने के लिए एक मिल-मान-अगर-नहीं-अशक्त:

मैं एक पैरामिट्रीकृत वर्ग कि इतने की तरह एक अस्थिर चर शामिल है।

क्या इन परिचालनों को सिंक्रनाइज़ करने की आवश्यकता है? क्या मैं निम्नलिखित विधि करने से दूर हो सकता हूं?

public void doSomething() { 
    String someString; 
    ... 
    if (lastValue != null) { 
     someString += lastValue.toString(); 
    } 
} 

या क्या मुझे एक सिंक्रनाइज़ ब्लॉक में शून्य जांच को चिपकने की ज़रूरत है?

public void doSomething() { 
    String someString; 
    ... 

    synchronized(this) { 
     if (lastValue != null) { 
      someString += lastValue.toString(); 
     } 
    } 
} 

मुझे पता है कि हो और सेट की तरह परमाणु संचालन के लिए, मैं तुल्यकालन (जैसे। public T getValue() { return lastValue; }) लागू किए बिना ठीक होना चाहिए। लेकिन मुझे गैर-परमाणु संचालन के बारे में निश्चित नहीं था।

+0

'someString + = lastValue.toStrin();' के रूप में 'someString + = (" "+ lastValue);' की मदद से आप से छुटकारा पाने के 'null' पूरी तरह जाँच करें। – dasblinkenlight

+4

@dasblinkenlight, सच है, लेकिन केवल तभी जब आप अपने परिणामस्वरूप स्ट्रिंग में "नल" शब्द के साथ ठीक हैं, तो आखिरी वैल्यू शून्य है। –

+0

@IanMcLaird आह, आप सही हैं, मैं भूल गया कि जावा ऐसा करता है (यह .NET है जो ऐसा नहीं करता है)। – dasblinkenlight

उत्तर

13

volatile दृश्यता की गारंटी देता है (एक थ्रेड द्वारा किए गए परिवर्तन अन्य धागे द्वारा देखे जाएंगे) लेकिन यह कई परिचालनों की परमाणुता की गारंटी नहीं देता है।

तो हाँ, lastValuenullif (lastValue != null) और के बीच someString += lastValue.toString(); और अपने कोड एक NullPointerException फेंक सकता है हो सकता है।

आप तुल्यकालन जोड़ने या तो कर सकते हैं (लेकिन आप सिंक्रनाइज़ करने के लिए सभी लिखने चर करने तक पहुँचता है की आवश्यकता होगी), या कि सरल उपयोग के मामले के लिए, यदि आप एक स्थानीय चर का उपयोग कर सकते हैं:

public void doSomething() { 
    String someString; 
    T lastValueCopy = lastValue; 
    if (lastValueCopy != null) { 
     someString += lastValueCopy.toString(); 
    } 
} 
+0

शून्य जांच में सिंक्रनाइज़ेशन क्यों जोड़ना अस्थिर चर के खिलाफ परमाणु संचालन के लिए सिंक्रनाइज़ेशन जोड़ने की आवश्यकता है? –

+0

क्या मैं सही ढंग से समझता हूं कि थ्रेड के लिए "पहले" और "बाद" की कोई धारणा नहीं है, सिवाय इसके कि जब वे किसी बिंदु पर सिंक्रनाइज़ हो जाते हैं? थ्रेड सेमेन्टिक्स किसी थ्रेड के लिए पुराने थ्रेड वैल्यू को देखने के लिए थ्रेड के लिए अनुमति देता है? – kutschkem

+0

@RoddyoftheFrozenPeas आप सही हैं, आपको केवल सभी लेखन कार्यों को सिंक्रनाइज़ करने की आवश्यकता है। यह आवश्यक है क्योंकि पारस्परिक बहिष्करण के लिए यहां 'सिंक्रनाइज़' का उपयोग किया जाता है, यानी यह सुनिश्चित करना कि कोई थ्रेड उन दो पंक्तियों के बीच आपके चर को संशोधित नहीं करता है। यह केवल तभी काम कर सकता है जब परिवर्तक को लिखने की कोशिश कर रहे सभी थ्रेड उस लॉक को प्राप्त करने की आवश्यकता हो। – assylias

2

इस पर निर्भर है प्रकार के गुण टी। सबसे सरल मामले में टी एक अपरिवर्तनीय प्रकार है, जो कि आप जो भी पढ़ते हैं उसका वह मूल्य है, यह बाद में इसके आंतरिक राज्य को नहीं बदलेगा। इस मामले में आपको कोई सिंक्रनाइज़ेशन की आवश्यकता नहीं है, बस स्थानीय चर में संदर्भ पढ़ें और जब तक आपको आवश्यकता हो तब तक इसके साथ काम करें।

यदि टी एक उत्परिवर्तनीय प्रकार है, तो आपको इसके साथ काम करते समय अपने राज्य को बदलने के उदाहरण के खिलाफ सुरक्षा की आवश्यकता है। इस मामले में आपको सिंक्रनाइज़ेशन की आवश्यकता होती है जो विशेष रूप से सुनिश्चित करता है कि टी का उदाहरण सुरक्षित है। पर सिंक्रनाइज़ करना यह आमतौर पर यह सुनिश्चित नहीं करता है कि, यह आपको किसी अन्य स्थान से टी के राज्य को बदलने से नहीं रोकता है। किसी विशिष्ट टी के लिए उचित लॉक नियमों द्वारा परिभाषित किया जाना चाहिए (और कोई नियम तत्व नहीं है जिससे आप उन नियमों को तोड़ न दें)।

विशेष मामले में टी व्यवहार्य है और आपने को यह उचित लॉक होने के लिए परिभाषित किया है, तो आपको सिंक्रनाइज़ेशन की आवश्यकता है - लेकिन आपको अब अस्थिरता की आवश्यकता नहीं है।

ने कहा कि सिंक्रनाइज़ दिखने के साथ संयोग में अस्थिरता का उपयोग संदिग्ध दिखता है।

+0

@loki जरूरी नहीं है, लेकिन जब यह दिखाई देता है तो यह एक स्थिर स्थिति में होगा। यदि ऑब्जेक्ट अपरिवर्तनीय नहीं है, जब यह दिखाई देता है, तो थ्रेड ऑब्जेक्ट को कुछ फ़ील्ड के साथ ठीक से बनाया जा सकता है और कुछ फ़ील्ड डिफ़ॉल्ट मान (झूठी, 0, शून्य)। – assylias

0

समांतर प्रसंस्करण डेटा को उनके मूल के संदर्भों की अद्यतन करने की गारंटी नहीं देता है। इस मामले में, आपको संदर्भ वस्तु के रूप में संचालित पर एक स्पष्ट सिंक्रनाइज़ेशन करना होगा। सिंक्रनाइज़ का उपयोग करें, प्रतीक्षा करें और इसे सूचित करें। पर

अधिक विवरण: नए सिरे से लिखना http://oracle2java.blogspot.com.br/2013/12/java-sincronizar-referencia-entre.html

संबंधित मुद्दे