2009-06-13 15 views
11

संभवत: इसी तरह के प्रश्न:डिफ़ॉल्ट रूप से जावा अस्थिरता में चर क्यों नहीं हैं?

Do you ever use the volatile keyword in Java?


आज मैं अपनी खेल डिबगिंग किया गया था; यह एक बहुत मुश्किल थ्रेडिंग समस्या थी जो हर कुछ मिनटों में दिखाई देगी, लेकिन पुन: पेश करना मुश्किल था। तो सबसे पहले मैंने अपनी प्रत्येक विधियों में synchronized कीवर्ड जोड़ा। वह काम नहीं किया। फिर मैंने प्रत्येक क्षेत्र में volatile कीवर्ड जोड़ा। समस्या सिर्फ खुद को ठीक लग रहा था।

कुछ प्रयोगों के बाद मुझे पता चला कि जिम्मेदार क्षेत्र GameState ऑब्जेक्ट था जो मेरे खेल की वर्तमान स्थिति का ट्रैक रखता था, जो या तो खेल या व्यस्त हो सकता है। व्यस्त होने पर, गेम उपयोगकर्ता इनपुट को अनदेखा करता है। मेरे पास एक धागा था जो लगातार state चर बदल गया, जबकि इवेंट थ्रेड state चर बदलता है। हालांकि, एक थ्रेड परिवर्तनीय को बदलने के बाद, अन्य थ्रेड के लिए परिवर्तनों को पहचानने में कई सेकंड लगते हैं, जो अंततः समस्या का कारण बनता है।

यह राज्य चर volatile बनाकर तय हुई थी।

डिफ़ॉल्ट रूप से जावा volatile में चर क्यों नहीं हैं और volatile कीवर्ड का उपयोग न करने का कोई कारण क्या है?

+11

इसी कारण से विधियों को डिफ़ॉल्ट रूप से सिंक्रनाइज़ नहीं किया जाता है। –

+6

@ एमपी: मुझे ऐसा नहीं लगता है। अस्थिर और सिंक्रनाइज़ समकक्ष नहीं हैं: अस्थिरता डेडलॉक्स का कारण नहीं बन सकती है। –

उत्तर

32

एक लंबी कहानी लघु, अस्थिर चर बनाने के लिए - वे जावा या सी # में हों - कभी भी थ्रेड के भीतर स्थानीय रूप से कैश नहीं किया जाता है। जब तक आप एक मल्टीप्रोसेसर/मल्टीकोर सीपीयू से अलग कोर पर निष्पादित धागे के साथ काम नहीं कर रहे हैं, तब तक इसका कोई प्रभाव नहीं पड़ता है, क्योंकि वे एक ही कैश को देख रहे होंगे। जब आप चर को अस्थिर घोषित करते हैं, तो सभी पढ़ते हैं और लिखते हैं और सीधे मुख्य मुख्य स्मृति स्थान पर जाते हैं; इसमें कोई कैश शामिल नहीं है। ऑप्टिमाइज़ेशन की बात आती है और इस तरह अनावश्यक रूप से करने के लिए इसका प्रभाव पड़ता है (जब अधिकांश चर को अस्थिर होने की आवश्यकता नहीं होती है) अपेक्षाकृत छोटे लाभ के लिए एक प्रदर्शन जुर्माना (जैसा कि यह हो सकता है या नहीं हो सकता है) को बढ़ावा देगा।

+6

यहां तक ​​कि एक कोर प्रोसेसर के साथ, कंपाइलर (जेआईटी कंपाइलर समेत) चर के उपयोग को अनुकूलित करने का निर्णय ले सकता है। –

+0

@ क्रिस: मैं एक .NET पृष्ठभूमि से आया हूं, इसलिए जावा अलग हो सकता है, लेकिन मुझे नहीं लगता कि एक इंस्टेंस चर को ऑप्टिमाइज़ किया जा सकता है जब तक कि यह पता न लगे कि इसका कभी भी उपयोग नहीं किया गया था, और स्थानीय चर को अस्थिर घोषित नहीं किया जा सकता (वास्तव में इसकी आवश्यकता नहीं होगी), है ना? –

+8

@Adam: यह पूरी तरह से इसे अनुकूलित नहीं कर सकता है। हालांकि, "y = x * x" जैसी कुछ चीज केवल दो बार की बजाय एक्स के मान को प्राप्त करने के लिए स्मृति में जा सकती है। यह एक मामूली उदाहरण है ... अब कल्पना करें कि एक्स कुछ लूप में फैल गया है और कई बार चेक किया गया है। यदि संकलक कभी नहीं देखता है कि आप x का मान बदलते हैं, तो यह एक बार इसे पढ़ने और स्थानीय स्तर पर इसे रखने का फैसला कर सकता है। –

5

क्योंकि संकलक अस्थिर चर अनुकूलित नहीं कर सकते।

volatile संकलक कि चर किसी भी समय बदल सकते हैं बताता है। इसलिए, यह नहीं मान सकता कि चर बदल जाएगा और तदनुसार अनुकूलित नहीं होगा।

2

घोषणा चर अस्थिर आम तौर पर प्रदर्शन पर बहुत बड़ा प्रभाव पड़ता है। पारंपरिक सिंगल-थ्रेडेड सिस्टम पर, यह जानना बेहद आसान था कि अस्थिर होने की क्या आवश्यकता है; यह उन चीजों को था जो हार्डवेयर तक पहुंचे थे।

पर मल्टी-थ्रेडेड यह थोड़ा और अधिक जटिल हो सकता है, लेकिन मैं आम तौर पर जादू चर के Leau में theads के बीच डेटा गुजर संभालने के लिए सूचनाएं और ईवेंट कतार का उपयोग कर प्रोत्साहित करेगा। जावा में इससे कोई फर्क नहीं पड़ता; सी/सी ++ में आपको परेशानी होगी जब उन चर को अंतर्निहित हार्डवेयर द्वारा परमाणु रूप से सेट नहीं किया जा सकता है।

+0

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

+1

@Adam: जावा और सी # में, मुझे इतना यकीन नहीं है, हालांकि मुझे लगता है कि जेएनआई आपको कुछ गेम खेलने दे सकता है। एक सी/सी ++ पर्यावरण में, अस्थिरता यह इंगित करने के लिए महत्वपूर्ण थी कि इस स्मृति को चल रहे प्रोग्राम के अलावा कहीं और से बदला जा सकता है, यानी हार्डवेयर, जो उस स्मृति स्थान पर मैप किया गया है। चूंकि जावा और सी # आमतौर पर हार्डवेयर के करीब नहीं चलते हैं, यह एक अलग गेम हो सकता है। –

+0

@AdamRobinson: यहां तक ​​कि एक थ्रेडेड वातावरण में, जावा स्वतंत्र आदेशों को पुन: व्यवस्थित करने का अधिकार सुरक्षित रखता है। तो, उदाहरण के लिए: 'x = 1; वाई = 2; 'y = 2 में बदला जा सकता है; एक्स = 1; '। लेकिन 'x = z ++; y = z ++; 'y = z ++ में बदला नहीं जाना चाहिए; एक्स = जेड ++; '। JVM को उन दृश्यों को पुन: क्रमबद्ध नहीं करना चाहिए जिनके पास बाहरी दृश्यता है। उदाहरण के लिए 'x = 1; System.out.println ("x सेट है"); वाई = 2; 'फिर से आदेश नहीं दिया जा सकता है। यदि आप जावा बाहरी दृश्यता तर्क पर भरोसा नहीं करते हैं (कहें कि क्या आप वास्तविक स्मृति की निगरानी कर रहे हैं), तो आप वैरिएबल को उस चर के रूप में चिह्नित करने के लिए उपयोग कर सकते हैं जिसे अनुकूलित नहीं किया जाना चाहिए। –

6

जबकि अन्य उनका कहना है कि ऐसा क्यों अस्थिर करने के लिए डिफ़ॉल्ट एक बुरा विचार किया जाएगा में सही कर रहे हैं, वहाँ बनाने के लिए एक और बात है: वहाँ बहुत संभावना अपने कोड में एक बग है। वेरिएबल्स को कभी-कभी अस्थिर बनाने की आवश्यकता होती है: चरों तक पहुंच को सिंक्रनाइज़ करने के लिए हमेशा एक तरीका होता है (या तो सिंक्रनाइज़ किए गए कीवर्ड द्वारा, या java.util.concurrency से AtomicXxx ऑब्जेक्ट्स का उपयोग करके): अपवादों में जेएनआई कोड इन्हें जोड़कर शामिल किया जाएगा (जो बाध्य नहीं है सिंक्रनाइज़ेशन निर्देश)।

तो अस्थिर जोड़ने की बजाय, आप यह जानना चाहेंगे कि समस्या का समाधान क्यों हुआ। इसे हल करने का यह एकमात्र तरीका नहीं है, और शायद एक बेहतर तरीका है।

+1

हालांकि यह सच हो सकता है या नहीं भी हो सकता है, यह पूरी तरह से संभव है कि वह लॉक-फ्री कोड लिखने का प्रयास कर रहा है। यदि आप जो भी कर रहे हैं, वह पढ़ना पढ़ रहा है, तो एक विशेष लॉक प्राप्त करना या सेमफोर का उपयोग करना हमेशा आवश्यक नहीं होता है। बस मेरा .02 –

+0

सच है, यह संभव है, और वाष्पशीलता एक ही रास्ता है। लेकिन अस्थिरता के ऊपरी हिस्से (अन्य कारण बताते हैं) स्पष्ट सिंकिंग से अधिक हो सकते हैं, और कम होने की संभावना नहीं है। विशेष रूप से यह देखते हुए कि कैसे अनुकूलित j.u.concurrent impls हैं, या यहां तक ​​कि सादे पुराने सिंक भी हैं। – StaxMan

10

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

java.util.concurrent में अन्य बिल्डिंग ब्लॉक का उपयोग करने के लिए अधिक सुखद विकल्प है, जिनमें से कुछ लॉक-फ्री हैं, लेकिन अपने सिर से गड़बड़ न करें जितना आप इसे कम स्तर पर करने की कोशिश कर रहे हैं।

अस्थिरता की अपनी प्रदर्शन लागत है, और अधिकतर कोड को उन लागतों का कारण बनने का कोई कारण नहीं है।

8

व्यक्तिगत रूप से मुझे लगता है कि फ़ील्ड डिफ़ॉल्ट रूप से अंतिम होनी चाहिए और केवल एक अतिरिक्त कीवर्ड के साथ उत्परिवर्तनीय होना चाहिए, लेकिन वह नाव समय के साथ पहले ही पहुंची है। ;)

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

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