जावा में वाष्पशील बनाम स्थैतिक


265

क्या यह कहना सही है कि staticसभी वस्तुओं volatileके लिए मूल्य की एक प्रति और सभी धागे के लिए मूल्य की एक प्रति का मतलब है?

वैसे staticभी सभी थ्रेड्स के लिए एक वैरिएबल वैल्यू भी एक वैल्यू है, फिर हम क्यों जाएं volatile?


के अस्थिर आधिकारिक स्पष्टीकरण: cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#volatile
वादज़्मी

जवाबों:


365

जावा में एक स्थिर चर की घोषणा करते हुए , इसका मतलब है कि केवल एक ही प्रति होगी, चाहे वह कक्षा की कितनी भी वस्तुएं क्यों न बनाई गई हो। वेरिएबल बिल्कुल भी उपलब्ध नहीं होने के बावजूद उपलब्ध होगा 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कक्षा का उपयोग करें ।


7
वाष्पशील संशोधक गारंटी देता है कि किसी भी फ़ील्ड को पढ़ने वाले किसी भी थ्रेड को सबसे हाल ही में लिखा गया मान दिखाई देगा, इसलिए यह आवश्यक है कि चर को कई थ्रेड के बीच साझा किया गया है और आपको इस सुविधा की आवश्यकता है, यह आपके उपयोग के मामले पर निर्भर करता है।
स्टिव्लो

5
जब आप "स्थानीय रूप से कैशेड" कहते हैं तो कैश क्या है? सीपीयू कैश, किसी तरह का जेवीएम कैश?
मर्ट इनन

6
@mertinan हाँ, चर प्रोसेसर या कोर के पास कैश में हो सकता है। अधिक जानकारी के लिए cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html देखें ।
22

15
'अस्थिर' है नहीं मतलब 'ऑब्जेक्ट प्रति एक चर'। 'स्टेटिक' की अनुपस्थिति यही करती है। -1 ओपी की ओर से इस प्रारंभिक गलत धारणा को स्पष्ट करने में विफल।
लोर्न

27
@EJP मुझे लगा कि वाक्य "एक चर को अस्थिर के रूप में घोषित करना, प्रत्येक वस्तु के लिए एक चर होगा। इसलिए सतह पर ऐसा लगता है कि एक सामान्य चर से कोई अंतर नहीं है" यह समझा रहा था कि, मैंने जोड़ा है और स्थिर नहीं है , लेख को संपादित करने और शब्दों को बेहतर बनाने के लिए स्वतंत्र महसूस करें।
स्टिवलो

288

स्थैतिक और अस्थिर के बीच अंतर:

स्टैटिक वेरिएबल : यदि दो थ्रेड्स (मान लें t1और t2) एक ही ऑब्जेक्ट को एक्सेस कर रहे हैं और एक वैरिएबल को अपडेट कर रहे हैं जिसे स्टैटिक घोषित किया गया है, तो इसका मतलब है t1और t2अपने संबंधित कैश में उसी ऑब्जेक्ट (स्टैटिक वेरिएबल्स सहित) की अपनी स्थानीय प्रति बना सकते हैं, इसलिए अपडेट करें t1अपने स्थानीय कैश में स्थैतिक चर द्वारा किए गए अभ्यस्त कैश के लिए स्थिर चर में दर्शाते हैं t2

स्टैटिक वेरिएब का उपयोग ऑब्जेक्ट के संदर्भ में किया जाता है जहां एक ऑब्जेक्ट द्वारा किया गया अपडेट एक ही क्लास के अन्य सभी ऑब्जेक्ट्स में परिलक्षित होता है, लेकिन थ्रेड के संदर्भ में नहीं जहां स्टैटिक वेरिएबल में एक थ्रेड का अपडेट सभी परिवर्तनों को तुरंत प्रतिबिंबित करेगा धागे (उनके स्थानीय कैश में)।

वाष्पशील चर : यदि दो थ्रेड्स (मान लें t1और t2) एक ही ऑब्जेक्ट को एक्सेस कर रहे हैं और एक वैरिएबल को अपडेट कर रहे हैं जो कि अस्थिर के रूप में घोषित किया गया है तो इसका मतलब है t1और t2ऑब्जेक्ट के अपने स्थानीय कैश को वैरिएबल के रूप में घोषित किया जा सकता है । तो वाष्पशील चर की केवल एक मुख्य प्रति होगी जिसे विभिन्न थ्रेड द्वारा अद्यतन किया जाएगा और एक थ्रेड द्वारा किए गए अद्यतन को अस्थिर चर में तुरंत दूसरे थ्रेड को दर्शाया जाएगा।


6
नमस्कार @Som, कृपया मुझे सही करें अगर मैं गलत हूं। लेकिन आपको नहीं लगता कि यह कथन " लेकिन थ्रेड के संदर्भ में नहीं है जहां एक थ्रेड का स्टेटिक वैरिएबल का अपडेट सभी थ्रेड्स (अपने स्थानीय कैश में) में बदलाव को तुरंत दिखाएगा। " होना चाहिए "लेकिन संदर्भ में नहीं। थ्रेड का जहां स्टैटिक वैरिएबल में एक थ्रेड का अद्यतन << << >> सभी थ्रेड्स (अपने स्थानीय कैश में) में तुरंत परिवर्तन दर्शाते हैं। "
जयक्रांत

@ जिक्रत हाँ जो मेरे लिए बहुत उलझन की बात थी। मेरी समझ यह है कि आप सही हैं और यह उत्तर गलत है, जैसा लिखा है। मैं गलत होने पर भी सही होना चाहूंगा।
स्टुअर्ट

@ जिक्रत थ्रेड्स स्टैटिक वैरिएबल को कैश नहीं करते हैं, लेकिन, अपडेटेड स्टैटिक वैरिएबल को देखें।
सोम

@ तो फिर क्या आप पैरा को सही करना और हटाना चाहते हैं लेकिन थ्रेड के संदर्भ में नहीं । यह बहुत भ्रामक है। धन्यवाद
Jaikrat

अफसोस की बात है कि यह जवाब गलत है। आधुनिक सीपीयू पर, यहां तक ​​कि एक volatileचर को अलग सीपीयू कैश के बीच साझा किया जा सकता है। यह कोई समस्या नहीं प्रस्तुत करता है क्योंकि कैश इसे संशोधित करने से पहले कैश लाइन के अनन्य स्वामित्व पर बातचीत करता है।
डेविड श्वार्ट्ज

32

अन्य उत्तरों के अलावा, मैं इसके लिए एक छवि जोड़ना चाहूंगा (तस्वीर को समझना आसान हो जाता है)

यहां छवि विवरण दर्ज करें

staticवैरिएबल को व्यक्तिगत थ्रेड्स के लिए कैश्ड किया जा सकता है। बहु-थ्रेडेड वातावरण में यदि कोई थ्रेड अपने कैश्ड डेटा को संशोधित करता है, तो वह अन्य थ्रेड के लिए प्रतिबिंबित नहीं कर सकता है क्योंकि उनके पास इसकी एक प्रति है।

volatileघोषणा यह सुनिश्चित करती है कि थ्रेड्स डेटा को कैश नहीं करेंगे और केवल साझा कॉपी का उपयोग करेंगे

छवि स्रोत


1
स्थैतिक चर एक धागा के तहत वस्तुओं के बीच साझा किए जाते हैं? यह पढ़ा जाना चाहिए स्थैतिक चर सभी वस्तुओं के बीच साझा किए जाते हैं चाहे धागे की परवाह किए बिना।
cquezel

1
"अस्थिर चर को कई थ्रेड्स (इसलिए ऑब्जेक्ट्स के साथ) के बीच साझा किया जाता है।" अस्थिर नहीं बदलता है कि चर को कई थ्रेड्स या ऑब्जेक्ट्स के बीच कैसे साझा किया जाता है। यह बदलता है कि मूल्य को कैश करने के लिए रनटाइम की अनुमति कैसे दी जाती है।
cquezel 20

1
स्टैटिक वैरिएबल के बारे में आपकी टिप्पणी नॉन स्टैटिक पर भी लागू होती है और "कैश्ड हो जाएगी" और "रिफ्लेक्ट नहीं होगी" को शायद रीफ़्रैश किया जाए "कैश्ड हो सकता है" और "रिफ्लेक्ट नहीं हो सकता"।
cquezel

4
मैं बहुत उलझन में था। इस तस्वीर ने मेरे सारे सवाल साफ़ कर दिए!
Vins

5

मुझे लगता है staticऔर मेरा volatileकोई संबंध नहीं है। मेरा सुझाव है कि आप परमाणु पहुंच को समझने के लिए जावा ट्यूटोरियल पढ़ते हैं , और परमाणु पहुंच का उपयोग क्यों करते हैं, यह समझें कि इंटरलेव्ड क्या है , आपको उत्तर मिलेगा।


4

समान्य शब्दों में,

  1. स्थैतिक : staticचर किसी भी वस्तु के बजाय वर्ग से जुड़े होते हैं । कक्षा का हर उदाहरण एक वर्ग चर साझा करता है, जो स्मृति में एक निश्चित स्थान पर है

  2. वाष्पशील : यह खोजशब्द कक्षा और उदाहरण चर दोनों पर लागू होता है ।

वाष्पशील चरों का उपयोग करने से मेमोरी की संगति त्रुटियों का खतरा कम हो जाता है, क्योंकि वाष्पशील चर के लिए कोई भी लिखता है, उसी चर के बाद के पठन के साथ संबंध होने से पहले होता है। इसका अर्थ है कि एक अस्थिर चर में परिवर्तन हमेशा अन्य थ्रेड्स के लिए दिखाई देते हैं

इस पर एक नज़र डालें लेख द्वारा Javin Paul एक बेहतर तरीके से अस्थिर चर को समझने के लिए।

यहां छवि विवरण दर्ज करें

volatileकीवर्ड की अनुपस्थिति में , प्रत्येक थ्रेड के स्टैक में चर का मूल्य भिन्न हो सकता है। वैरिएबल को बनाने के रूप में volatile, सभी थ्रेड्स को उनकी कार्यशील मेमोरी में समान मूल्य मिलेगा और मेमोरी संगतता त्रुटियों से बचा गया है।

यहाँ शब्द variableया तो static(वर्ग) चर या instance(वस्तु) चर हो सकता है।

आपकी क्वेरी के बारे में:

वैसे भी सभी थ्रेड्स के लिए एक स्टैटिक वैरिएबल वैल्यू भी एक वैल्यू होने वाली है, फिर हम अस्थिर क्यों जाएं?

यदि मुझे instanceअपने आवेदन में चर की आवश्यकता है , तो मैं staticचर का उपयोग नहीं कर सकता । staticचर के मामले में भी , थ्रेड कैश के कारण स्थिरता की गारंटी नहीं है जैसा कि आरेख में दिखाया गया है।

volatileचरों का उपयोग करने से मेमोरी की संगति त्रुटियों का खतरा कम हो जाता है, क्योंकि कोई भी वाष्पशील चर लिखता है, उसी चर के बाद के पठन के साथ एक होने से पहले संबंध स्थापित करता है। इसका मतलब है कि एक अस्थिर चर में परिवर्तन हमेशा अन्य थ्रेड्स के लिए दिखाई देते हैं।

क्या अधिक है, इसका मतलब यह भी है कि जब एक थ्रेड अस्थिर संस्करण को पढ़ता है, तो यह अस्थिरता के लिए न केवल नवीनतम परिवर्तन देखता है, बल्कि कोड का साइड इफेक्ट भी होता है जो परिवर्तन का नेतृत्व करता है => मेमोरी चर त्रुटियों को अभी भी अस्थिर चर के साथ संभव है । साइड इफेक्ट्स से बचने के लिए, आपको सिंक्रनाइज़ किए गए चर का उपयोग करना होगा। लेकिन जावा में एक बेहतर उपाय है।

सिंक्रनाइज़ कोड के माध्यम से इन चर को एक्सेस करने की तुलना में सरल परमाणु चर पहुंच का उपयोग करना अधिक कुशल है

java.util.concurrentपैकेज में कुछ कक्षाएं परमाणु विधियां प्रदान करती हैं जो सिंक्रनाइज़ेशन पर भरोसा नहीं करती हैं।

अधिक जानकारी के लिए इस उच्च स्तरीय संगोष्ठी नियंत्रण लेख का संदर्भ लें ।

विशेष रूप से परमाणु चर पर एक नज़र है ।

संबंधित एसई प्रश्न:

वाष्पशील बनाम परमाणु

वाष्पशील बूलियन बनाम एटॉमिक बुलियन

जावा में अस्थिर और सिंक्रनाइज़ के बीच अंतर


मैं वास्तव में इस जवाब की सराहना करता हूं। मुझे पता था कि volatileपहले क्या है , लेकिन, यह जवाब मेरे लिए बहुत कुछ स्पष्ट करता है कि मुझे अभी भी चर के volatileसाथ उपयोग करने की आवश्यकता क्यों है static
चाकलादेर असफाक आरव

वाष्पशील: यह खोजशब्द कक्षा और उदाहरण चर दोनों पर लागू होता है। आपने ऊपर जो बयान दिया है वह कक्षा के लिए लागू होने के संबंध में गलत है। चर पर लागू होने वाले केवल दो प्रमुख शब्द अस्थिर और क्षणिक हैं। इतना अस्थिर अभ्यस्त वर्ग के लिए लागू होता है।
एएसआर

वाष्पशील वर्ग (स्थिर) चर पर लागू होता है। Google में डबल लॉक सिंगलटन लिंक देखें और आप पा सकते हैं कि आपकी समझ गलत है। stackoverflow.com/questions/18093735/…
रवींद्र बाबू

निजी स्थिर अस्थिर वैध घोषणा है।
रवींद्र बाबू

0

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

अब यदि मल्टी-थ्रेडिंग परिवेश में स्थिर चर का उपयोग किया जाता है तो कोई समस्या होगी अगर कोई इससे अपेक्षित परिणाम प्राप्त करता है। जैसा कि प्रत्येक थ्रेड की अपनी प्रतिलिपि होती है, फिर एक थ्रेड से स्टैटिक वैरिएबल पर कोई वृद्धि या गिरावट दूसरे थ्रेड में प्रतिबिंबित नहीं हो सकती है।

यदि कोई स्थिर चर से वांछित परिणाम की उम्मीद करता है तो मल्टी-थ्रेडिंग में स्थिर के साथ अस्थिर का उपयोग करें तो सब कुछ हल हो जाएगा।


0

निश्चित नहीं है कि स्थिर चर स्थानीय स्मृति में थ्रेडेड हैं या नहीं। लेकिन जब मैंने दो थ्रेड्स (T1, T2) को एक ही ऑब्जेक्ट (obj) तक पहुँचाया और जब T1 थ्रेड द्वारा स्टैटिक वैरिएबल में अपडेट किया गया तो यह T2 में परिलक्षित हुआ।


-2

यदि हम किसी चर को स्थैतिक घोषित करते हैं, तो चर की केवल एक प्रति होगी। इसलिए, जब भी विभिन्न धागे उस चर का उपयोग करते हैं, तो चर के लिए केवल एक अंतिम मूल्य होगा (चूंकि चर के लिए केवल एक मेमोरी स्थान आवंटित किया गया है)।

यदि एक चर को अस्थिर के रूप में घोषित किया जाता है, तो सभी थ्रेड्स की चर की अपनी प्रति होगी, लेकिन मुख्य मेमोरी से मान लिया जाता है। इसलिए, सभी थ्रेड्स में चर का मूल्य समान होगा।

तो, दोनों मामलों में, मुख्य बिंदु यह है कि चर का मूल्य सभी थ्रेड्स में समान है।


15
यदि एक चर को अस्थिर के रूप में घोषित किया जाता है, तो सभी थ्रेड्स में चर की अपनी प्रति होगी लेकिन मुख्य मेमोरी से मान लिया जाता है। => सही है। तो, सभी थ्रेड्स में वैरिएबल का मान समान होगा। => गलत, प्रत्येक थ्रेड एक ही ऑब्जेक्ट के लिए समान मान का उपयोग करेगा, लेकिन प्रत्येक ऑब्जेक्ट की अपनी प्रतिलिपि होगी।
5
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.