यह समझना महत्वपूर्ण है कि थ्रेड सुरक्षा के दो पहलू हैं ।
- निष्पादन नियंत्रण, और
- मेमोरी दृश्यता
जब कोड निष्पादित होता है तो नियंत्रण के साथ पहले करना होता है (उस क्रम में जिसमें निर्देश निष्पादित किए जाते हैं) और क्या यह समवर्ती रूप से निष्पादित हो सकता है, और दूसरा ऐसा करने के लिए जब क्या किया गया है की स्मृति में प्रभाव अन्य थ्रेड्स को दिखाई देते हैं। क्योंकि प्रत्येक CPU के बीच कैश का कई स्तर होता है और मुख्य मेमोरी, विभिन्न CPU या कोर पर चलने वाले थ्रेड्स "मेमोरी" को किसी भी समय अलग-अलग समय पर देख सकते हैं क्योंकि थ्रेड को मुख्य मेमोरी की निजी प्रतियों को प्राप्त करने और काम करने की अनुमति होती है।
उपयोग करना synchronized
किसी भी अन्य धागे को एक ही वस्तु के लिए मॉनिटर (या लॉक) प्राप्त करने से रोकता है , जिससे समवर्ती पर निष्पादित होने से एक ही ऑब्जेक्ट पर सिंक्रनाइज़ेशन द्वारा संरक्षित सभी कोड ब्लॉक को रोका जा सके । सिंक्रोनाइज़ेशन एक "होता-पहले" मेमोरी बैरियर भी बनाता है, जिससे मेमोरी विजिबिलिटी में बाधा उत्पन्न होती है कि कुछ भी करने के लिए कुछ थ्रेड रिलीज एक लॉक दूसरे थ्रेड को प्रकट होता है बाद में उसी लॉक को प्राप्त होता है जो लॉक हासिल करने से पहले हुआ था। व्यावहारिक रूप से, वर्तमान हार्डवेयर पर, यह आमतौर पर सीपीयू कैश के फ्लशिंग का कारण बनता है जब एक मॉनीटर अधिग्रहित किया जाता है और जारी होने पर मुख्य मेमोरी में लिखता है, जो दोनों (अपेक्षाकृत) महंगे हैं।
volatile
दूसरी ओर, उपयोग करना , सभी एक्सेस (वाचन या लिखना) को वाष्पशील चर में मुख्य मेमोरी में होने के लिए मजबूर करता है, जो कि प्रभावी रूप से वाष्पशील चर को सीपीयू कैश से बाहर रखता है। यह कुछ क्रियाओं के लिए उपयोगी हो सकता है जहां यह आवश्यक है कि चर की दृश्यता सही हो और अभिगम का क्रम महत्वपूर्ण न हो। का उपयोग कर के volatile
उपचार में परिवर्तन करने के लिए long
और double
उन तक पहुँचने के लिए उन्हें परमाणु की आवश्यकता होती है; कुछ (पुराने) हार्डवेयर पर इसे ताले की आवश्यकता हो सकती है, हालांकि आधुनिक 64 बिट हार्डवेयर पर नहीं। जावा 5+ के लिए नए (JSR-133) मेमोरी मॉडल के तहत, अस्थिरता के शब्दार्थ को मेमोरी विजिबिलिटी और इंस्ट्रक्शन आर्डर ( http://www.cs.umd.edu देखें) के संबंध में लगभग मजबूत किया गया है । /users/pugh/java/memoryModel/jsr-133-faq.html#volatile)। दृश्यता के प्रयोजनों के लिए, एक अस्थिर क्षेत्र में प्रत्येक का उपयोग आधा तुल्यकालन की तरह होता है।
नए मेमोरी मॉडल के तहत, यह अभी भी सच है कि अस्थिर चर को एक दूसरे के साथ फिर से व्यवस्थित नहीं किया जा सकता है। अंतर यह है कि अब यह सामान्य नहीं है कि उनके आस-पास के सामान्य क्षेत्र को फिर से व्यवस्थित करना आसान हो। वाष्पशील क्षेत्र में लिखने से मॉनिटर रिलीज़ के समान मेमोरी इफेक्ट होता है, और वाष्पशील क्षेत्र से पढ़ने पर मॉनिटर के अधिग्रहण के समान मेमोरी इफेक्ट होता है। वास्तव में, अस्थिर क्षेत्र की पुन: क्रम पर नए स्मृति मॉडल स्थानों सख्त कमी अन्य क्षेत्र पहुंच, अस्थिर या नहीं, कुछ भी है कि सूत्र में बाँधना दिखाई दे रही थी साथ पहुँचता क्योंकि A
जब यह लिखते को अस्थिर क्षेत्र f
सूत्र में बाँधना दिखाई देने लगता है B
जब इसे पढ़ता है f
।
- JSR 133 (जावा मेमोरी मॉडल) FAQ
इसलिए, अब मेमोरी बैरियर के दोनों रूप (वर्तमान JMM के तहत) एक निर्देश पुन: आदेश अवरोध पैदा करते हैं, जो कंपाइलर या रन-टाइम को अवरोध के दौरान पुन: आदेश देने वाले निर्देशों से रोकता है। पुरानी झामुमो में अस्थिरता ने फिर से आदेश देने से नहीं रोका। यह महत्वपूर्ण हो सकता है, क्योंकि मेमोरी बाधाओं के अलावा केवल सीमित सीमा है, जो किसी विशेष थ्रेड के लिए , कोड का शुद्ध प्रभाव समान है जैसे कि यदि निर्देशों को ठीक उसी क्रम में निष्पादित किया जाता है जिसमें वे दिखाई देते हैं स्रोत।
वाष्पशील का एक उपयोग एक साझा लेकिन अपरिवर्तनीय वस्तु के लिए किया जाता है, जिसे मक्खी पर फिर से बनाया जाता है, जिसमें कई अन्य धागे अपने निष्पादन चक्र में किसी विशेष बिंदु पर वस्तु का संदर्भ लेते हैं। एक बार प्रकाशित होने के बाद, पुनः निर्मित ऑब्जेक्ट का उपयोग शुरू करने के लिए दूसरे थ्रेड्स की आवश्यकता होती है, लेकिन पूर्ण सिंक्रनाइज़ेशन के अतिरिक्त ओवरहेड की आवश्यकता नहीं होती है और यह परिचर विवाद और कैश फ्लशिंग है।
// Declaration
public class SharedLocation {
static public SomeObject someObject=new SomeObject(); // default object
}
// Publishing code
// Note: do not simply use SharedLocation.someObject.xxx(), since although
// someObject will be internally consistent for xxx(), a subsequent
// call to yyy() might be inconsistent with xxx() if the object was
// replaced in between calls.
SharedLocation.someObject=new SomeObject(...); // new object is published
// Using code
private String getError() {
SomeObject myCopy=SharedLocation.someObject; // gets current copy
...
int cod=myCopy.getErrorCode();
String txt=myCopy.getErrorText();
return (cod+" - "+txt);
}
// And so on, with myCopy always in a consistent state within and across calls
// Eventually we will return to the code that gets the current SomeObject.
खासतौर पर अपने रीड-अपडेट-राइट सवाल पर बोलना। निम्नलिखित असुरक्षित कोड पर विचार करें:
public void updateCounter() {
if(counter==1000) { counter=0; }
else { counter++; }
}
अब अपडेटकाउंटर () विधि अनसंकट्रेंडेड के साथ, एक ही समय में दो धागे इसे दर्ज कर सकते हैं। क्या हो सकता है के कई क्रमों के बीच, एक यह है कि थ्रेड -1 काउंटर == 1000 के लिए परीक्षण करता है और इसे सही पाता है और फिर निलंबित कर दिया जाता है। फिर थ्रेड -2 एक ही परीक्षण करता है और इसे सही भी देखता है और निलंबित कर दिया जाता है। फिर थ्रेड -1 फिर से शुरू होता है और काउंटर को 0. पर सेट करता है और फिर थ्रेड -2 फिर से शुरू होता है और फिर से 0 पर सेट होता है क्योंकि यह थ्रेड -1 से अपडेट से चूक गया था। यह तब भी हो सकता है जब थ्रेड स्विचिंग नहीं होती है जैसा कि मैंने वर्णित किया है, लेकिन सिर्फ इसलिए कि काउंटर की दो अलग-अलग कैश्ड प्रतियां दो अलग-अलग सीपीयू कोर में मौजूद थीं और प्रत्येक थ्रेड एक अलग कोर पर चलता था। उस बात के लिए, एक धागा एक मूल्य पर काउंटर हो सकता है और दूसरा केवल कैशिंग के कारण कुछ पूरी तरह से अलग मूल्य पर काउंटर हो सकता है।
इस उदाहरण में जो महत्वपूर्ण है वह यह है कि चर काउंटर को मुख्य मेमोरी से कैश में पढ़ा गया था, कैश में अपडेट किया गया था और केवल मुख्य मेमोरी में कुछ अनिश्चित बिंदु पर बाद में लिखा गया था जब मेमोरी बाधा उत्पन्न हुई या जब कैश मेमोरी कुछ और के लिए आवश्यक थी। volatile
इस कोड की थ्रेड-सुरक्षा के लिए काउंटर बनाना अपर्याप्त है, क्योंकि अधिकतम और असाइनमेंट के लिए परीक्षण असतत संचालन हैं, जिसमें वृद्धि भी शामिल है जो गैर-परमाणु read+increment+write
मशीन निर्देशों का एक सेट है , जैसे कुछ:
MOV EAX,counter
INC EAX
MOV counter,EAX
अस्थिर चर केवल तब उपयोगी होते हैं जब उन पर किए गए सभी ऑपरेशन "परमाणु" होते हैं, जैसे कि मेरा उदाहरण जहां पूरी तरह से बनाई गई वस्तु का संदर्भ केवल पढ़ा या लिखा गया है (और, वास्तव में, आमतौर पर यह केवल एक बिंदु से लिखा जाता है)। एक अन्य उदाहरण एक कॉपी-ऑन-राइट लिस्ट का समर्थन करने वाला एक अस्थिर सरणी संदर्भ होगा, बशर्ते कि सरणी को केवल संदर्भ की स्थानीय कॉपी लेते हुए पहले पढ़ा गया हो।