क्या यह कहना सही है कि static
सभी वस्तुओं volatile
के लिए मूल्य की एक प्रति और सभी धागे के लिए मूल्य की एक प्रति का मतलब है?
वैसे static
भी सभी थ्रेड्स के लिए एक वैरिएबल वैल्यू भी एक वैल्यू है, फिर हम क्यों जाएं volatile
?
क्या यह कहना सही है कि static
सभी वस्तुओं volatile
के लिए मूल्य की एक प्रति और सभी धागे के लिए मूल्य की एक प्रति का मतलब है?
वैसे static
भी सभी थ्रेड्स के लिए एक वैरिएबल वैल्यू भी एक वैल्यू है, फिर हम क्यों जाएं volatile
?
जवाबों:
जावा में एक स्थिर चर की घोषणा करते हुए , इसका मतलब है कि केवल एक ही प्रति होगी, चाहे वह कक्षा की कितनी भी वस्तुएं क्यों न बनाई गई हो। वेरिएबल बिल्कुल भी उपलब्ध नहीं होने के बावजूद उपलब्ध होगा Objects
। हालाँकि, थ्रेड्स के स्थानीय रूप से कैश्ड मान हो सकते हैं।
जब एक चर अस्थिर होता है और स्थिर नहीं होता है , तो प्रत्येक के लिए एक चर होगा Object
। तो, सतह पर ऐसा लगता है कि सामान्य चर से कोई अंतर नहीं है, लेकिन स्थैतिक से पूरी तरह से अलग है । हालांकि, Object
खेतों के साथ भी , एक धागा स्थानीय रूप से एक चर मूल्य को कैश कर सकता है।
इसका मतलब यह है कि यदि दो थ्रेड्स समवर्ती रूप से एक ही ऑब्जेक्ट के एक वैरिएबल को अपडेट करते हैं, और वैरिएबल को अस्थिर नहीं घोषित किया जाता है, तो ऐसा मामला हो सकता है जिसमें थ्रेड में से एक में कैश का पुराना मूल्य हो।
यहां तक कि अगर आप कई थ्रेड्स के माध्यम से एक स्थिर मूल्य तक पहुंचते हैं, तो प्रत्येक थ्रेड की स्थानीय कैश्ड कॉपी हो सकती है! इससे बचने के लिए आप वैरिएबल को स्थिर अस्थिर घोषित कर सकते हैं और यह थ्रेड को हर बार वैश्विक मान पढ़ने के लिए मजबूर करेगा।
हालाँकि, वाष्पशील उचित सिंक्रनाइज़ेशन का विकल्प नहीं है!
उदाहरण के लिए:
private static volatile int counter = 0;
private void concurrentMethodWrong() {
counter = counter + 5;
//do something
counter = counter - 5;
}
concurrentMethodWrong
कई बार समवर्ती रूप से निष्पादित करने पर काउंटर का अंतिम मान शून्य से अलग हो सकता है!
समस्या को हल करने के लिए, आपको एक ताला लागू करना होगा:
private static final Object counterLock = new Object();
private static volatile int counter = 0;
private void concurrentMethodRight() {
synchronized (counterLock) {
counter = counter + 5;
}
//do something
synchronized (counterLock) {
counter = counter - 5;
}
}
या AtomicInteger
कक्षा का उपयोग करें ।
स्थैतिक और अस्थिर के बीच अंतर:
स्टैटिक वेरिएबल : यदि दो थ्रेड्स (मान लें t1
और t2
) एक ही ऑब्जेक्ट को एक्सेस कर रहे हैं और एक वैरिएबल को अपडेट कर रहे हैं जिसे स्टैटिक घोषित किया गया है, तो इसका मतलब है t1
और t2
अपने संबंधित कैश में उसी ऑब्जेक्ट (स्टैटिक वेरिएबल्स सहित) की अपनी स्थानीय प्रति बना सकते हैं, इसलिए अपडेट करें t1
अपने स्थानीय कैश में स्थैतिक चर द्वारा किए गए अभ्यस्त कैश के लिए स्थिर चर में दर्शाते हैं t2
।
स्टैटिक वेरिएब का उपयोग ऑब्जेक्ट के संदर्भ में किया जाता है जहां एक ऑब्जेक्ट द्वारा किया गया अपडेट एक ही क्लास के अन्य सभी ऑब्जेक्ट्स में परिलक्षित होता है, लेकिन थ्रेड के संदर्भ में नहीं जहां स्टैटिक वेरिएबल में एक थ्रेड का अपडेट सभी परिवर्तनों को तुरंत प्रतिबिंबित करेगा धागे (उनके स्थानीय कैश में)।
वाष्पशील चर : यदि दो थ्रेड्स (मान लें t1
और t2
) एक ही ऑब्जेक्ट को एक्सेस कर रहे हैं और एक वैरिएबल को अपडेट कर रहे हैं जो कि अस्थिर के रूप में घोषित किया गया है तो इसका मतलब है t1
और t2
ऑब्जेक्ट के अपने स्थानीय कैश को वैरिएबल के रूप में घोषित किया जा सकता है । तो वाष्पशील चर की केवल एक मुख्य प्रति होगी जिसे विभिन्न थ्रेड द्वारा अद्यतन किया जाएगा और एक थ्रेड द्वारा किए गए अद्यतन को अस्थिर चर में तुरंत दूसरे थ्रेड को दर्शाया जाएगा।
volatile
चर को अलग सीपीयू कैश के बीच साझा किया जा सकता है। यह कोई समस्या नहीं प्रस्तुत करता है क्योंकि कैश इसे संशोधित करने से पहले कैश लाइन के अनन्य स्वामित्व पर बातचीत करता है।
अन्य उत्तरों के अलावा, मैं इसके लिए एक छवि जोड़ना चाहूंगा (तस्वीर को समझना आसान हो जाता है)
static
वैरिएबल को व्यक्तिगत थ्रेड्स के लिए कैश्ड किया जा सकता है। बहु-थ्रेडेड वातावरण में यदि कोई थ्रेड अपने कैश्ड डेटा को संशोधित करता है, तो वह अन्य थ्रेड के लिए प्रतिबिंबित नहीं कर सकता है क्योंकि उनके पास इसकी एक प्रति है।
volatile
घोषणा यह सुनिश्चित करती है कि थ्रेड्स डेटा को कैश नहीं करेंगे और केवल साझा कॉपी का उपयोग करेंगे ।
मुझे लगता है static
और मेरा volatile
कोई संबंध नहीं है। मेरा सुझाव है कि आप परमाणु पहुंच को समझने के लिए जावा ट्यूटोरियल पढ़ते हैं , और परमाणु पहुंच का उपयोग क्यों करते हैं, यह समझें कि इंटरलेव्ड क्या है , आपको उत्तर मिलेगा।
समान्य शब्दों में,
स्थैतिक : static
चर किसी भी वस्तु के बजाय वर्ग से जुड़े होते हैं । कक्षा का हर उदाहरण एक वर्ग चर साझा करता है, जो स्मृति में एक निश्चित स्थान पर है
वाष्पशील : यह खोजशब्द कक्षा और उदाहरण चर दोनों पर लागू होता है ।
वाष्पशील चरों का उपयोग करने से मेमोरी की संगति त्रुटियों का खतरा कम हो जाता है, क्योंकि वाष्पशील चर के लिए कोई भी लिखता है, उसी चर के बाद के पठन के साथ संबंध होने से पहले होता है। इसका अर्थ है कि एक अस्थिर चर में परिवर्तन हमेशा अन्य थ्रेड्स के लिए दिखाई देते हैं
इस पर एक नज़र डालें लेख द्वारा Javin Paul
एक बेहतर तरीके से अस्थिर चर को समझने के लिए।
volatile
कीवर्ड की अनुपस्थिति में , प्रत्येक थ्रेड के स्टैक में चर का मूल्य भिन्न हो सकता है। वैरिएबल को बनाने के रूप में volatile
, सभी थ्रेड्स को उनकी कार्यशील मेमोरी में समान मूल्य मिलेगा और मेमोरी संगतता त्रुटियों से बचा गया है।
यहाँ शब्द variable
या तो static
(वर्ग) चर या instance
(वस्तु) चर हो सकता है।
आपकी क्वेरी के बारे में:
वैसे भी सभी थ्रेड्स के लिए एक स्टैटिक वैरिएबल वैल्यू भी एक वैल्यू होने वाली है, फिर हम अस्थिर क्यों जाएं?
यदि मुझे instance
अपने आवेदन में चर की आवश्यकता है , तो मैं static
चर का उपयोग नहीं कर सकता । static
चर के मामले में भी , थ्रेड कैश के कारण स्थिरता की गारंटी नहीं है जैसा कि आरेख में दिखाया गया है।
volatile
चरों का उपयोग करने से मेमोरी की संगति त्रुटियों का खतरा कम हो जाता है, क्योंकि कोई भी वाष्पशील चर लिखता है, उसी चर के बाद के पठन के साथ एक होने से पहले संबंध स्थापित करता है। इसका मतलब है कि एक अस्थिर चर में परिवर्तन हमेशा अन्य थ्रेड्स के लिए दिखाई देते हैं।
क्या अधिक है, इसका मतलब यह भी है कि जब एक थ्रेड अस्थिर संस्करण को पढ़ता है, तो यह अस्थिरता के लिए न केवल नवीनतम परिवर्तन देखता है, बल्कि कोड का साइड इफेक्ट भी होता है जो परिवर्तन का नेतृत्व करता है => मेमोरी चर त्रुटियों को अभी भी अस्थिर चर के साथ संभव है । साइड इफेक्ट्स से बचने के लिए, आपको सिंक्रनाइज़ किए गए चर का उपयोग करना होगा। लेकिन जावा में एक बेहतर उपाय है।
सिंक्रनाइज़ कोड के माध्यम से इन चर को एक्सेस करने की तुलना में सरल परमाणु चर पहुंच का उपयोग करना अधिक कुशल है
java.util.concurrent
पैकेज में कुछ कक्षाएं परमाणु विधियां प्रदान करती हैं जो सिंक्रनाइज़ेशन पर भरोसा नहीं करती हैं।
अधिक जानकारी के लिए इस उच्च स्तरीय संगोष्ठी नियंत्रण लेख का संदर्भ लें ।
विशेष रूप से परमाणु चर पर एक नज़र है ।
संबंधित एसई प्रश्न:
volatile
पहले क्या है , लेकिन, यह जवाब मेरे लिए बहुत कुछ स्पष्ट करता है कि मुझे अभी भी चर के volatile
साथ उपयोग करने की आवश्यकता क्यों है static
।
अस्थिर चर मूल्य पहुंच मुख्य मेमोरी से प्रत्यक्ष होगी। इसका उपयोग केवल बहु-थ्रेडिंग वातावरण में किया जाना चाहिए। स्थिर चर को एक बार लोड किया जाएगा। यदि इसका उपयोग एकल थ्रेड वातावरण में किया जाता है, भले ही चर की प्रति अपडेट की जाएगी और केवल एक थ्रेड होने के कारण इसे एक्सेस करने में कोई हानि नहीं होगी।
अब यदि मल्टी-थ्रेडिंग परिवेश में स्थिर चर का उपयोग किया जाता है तो कोई समस्या होगी अगर कोई इससे अपेक्षित परिणाम प्राप्त करता है। जैसा कि प्रत्येक थ्रेड की अपनी प्रतिलिपि होती है, फिर एक थ्रेड से स्टैटिक वैरिएबल पर कोई वृद्धि या गिरावट दूसरे थ्रेड में प्रतिबिंबित नहीं हो सकती है।
यदि कोई स्थिर चर से वांछित परिणाम की उम्मीद करता है तो मल्टी-थ्रेडिंग में स्थिर के साथ अस्थिर का उपयोग करें तो सब कुछ हल हो जाएगा।
निश्चित नहीं है कि स्थिर चर स्थानीय स्मृति में थ्रेडेड हैं या नहीं। लेकिन जब मैंने दो थ्रेड्स (T1, T2) को एक ही ऑब्जेक्ट (obj) तक पहुँचाया और जब T1 थ्रेड द्वारा स्टैटिक वैरिएबल में अपडेट किया गया तो यह T2 में परिलक्षित हुआ।
यदि हम किसी चर को स्थैतिक घोषित करते हैं, तो चर की केवल एक प्रति होगी। इसलिए, जब भी विभिन्न धागे उस चर का उपयोग करते हैं, तो चर के लिए केवल एक अंतिम मूल्य होगा (चूंकि चर के लिए केवल एक मेमोरी स्थान आवंटित किया गया है)।
यदि एक चर को अस्थिर के रूप में घोषित किया जाता है, तो सभी थ्रेड्स की चर की अपनी प्रति होगी, लेकिन मुख्य मेमोरी से मान लिया जाता है। इसलिए, सभी थ्रेड्स में चर का मूल्य समान होगा।
तो, दोनों मामलों में, मुख्य बिंदु यह है कि चर का मूल्य सभी थ्रेड्स में समान है।