मल्टीथ्रेडिंग की कला में महारत हासिल करें: बेहतर प्रदर्शन और सरलीकृत कोडिंग के लिए जावा में वाष्पशील कीवर्ड का उपयोग करना सीखें
जब हम जावा में कीवर्ड का उपयोग करते हैं तो दृश्यों के पीछे क्या होता है और यह सिंक्रनाइज़ेशनvolatile
के लिए पूर्ण प्रतिस्थापन क्यों नहीं है, इस पर एक संक्षिप्त नज़र
जावा के भीतर समवर्ती और बहु-थ्रेडेड अनुप्रयोगों की अस्पष्ट दुनिया में तल्लीन होने पर, आपको volatile
कीवर्ड आने की संभावना है।
इस कीवर्ड का उपयोग यह सुनिश्चित करने के लिए किया जा सकता है कि एक चर में कोई भी परिवर्तन तुरंत अन्य थ्रेड्स को दिखाई देगा, इसलिए हमारे डेटा को बासी, सिंक से बाहर और गलत होने से रोकने में मदद करता है।
जब आप इस कीवर्ड के आसपास के किसी भी दस्तावेज़ में खोदते हैं तो आप सीखेंगे कि यह सुनिश्चित करके काम करता है कि एक चर सीधे स्मृति से पढ़ा जाता है और कैश से नहीं। यह बहुत अच्छा है... लेकिन वास्तव में इसका क्या मतलब है?
हुड के नीचे कीवर्ड कैसे काम करता है ?volatile
बहु-थ्रेडेड एप्लिकेशन में, यह संभव है कि प्रत्येक थ्रेड एक अलग CPU के माध्यम से चलाया जाएगा।
वेरिएबल्स के साथ काम करते समय, प्रत्येक थ्रेड मुख्य मेमोरी से एक वेरिएबल के मान की प्रतिलिपि बना सकता है और प्रदर्शन को बेहतर बनाने के लिए इसे अपने स्वयं के CPU कैश में संग्रहीत कर सकता है।
यह सुनिश्चित करता है कि जब थ्रेड को किसी वेरिएबल के मान तक पहुँचने की आवश्यकता होती है, तो उसे CPU कैश से पढ़ा जा सकता है और उसे मुख्य मेमोरी तक पहुँचने की आवश्यकता नहीं होती है, जिससे समय की बचत होती है।
उपरोक्त उदाहरण में, myVar
गैर-वाष्पशील है और इसलिए जावा वर्चुअल मशीन (जेवीएम) किसी भी सीपीयू कैश से मुख्य मेमोरी में डेटा को पढ़ता या लिखता है, इसके आधार पर डेटा सिंक से बाहर हो सकता है।
उदाहरण के लिए, यदि कोई एक थ्रेड myVar
5 के मान को अद्यतन करता है, तो इस बात की कोई गारंटी नहीं है कि कब का मान myVar
CPU कैश से मुख्य मेमोरी में वापस लिखा जाता है।
इसका मतलब यह है कि myVar
सीपीयू कैश में से एक का मान मुख्य मेमोरी के समान नहीं हो सकता है, जिससे थ्रेड्स के बीच अलग-अलग मान हो सकते हैं।
चर बनाकरvolatile
और इस प्रकार सीपीयू कैश के विपरीत हमेशा मुख्य मेमोरी से मूल्य पढ़ना और लिखना, इस समस्या से बचा जा सकता है।
आपके कोड के लिए इसका क्या अर्थ है?
इसलिए हम इसका उपयोग कर सकते हैंvolatile
हमारे कोड में कीवर्ड यह सुनिश्चित करने के लिए कि हम हमेशा अपने मूल्यों को मुख्य मेमोरी से पढ़ते हैं न कि किसी विशिष्ट CPU कैश से।
नीचे की कक्षा myVar
में नहीं है volatile
। यदि हमारे पास 1 थ्रेड है जो पढ़ता है और अपडेट करता है myVar
, जबकि कई अन्य थ्रेड्स से पढ़ रहे हैं myVar
, जल्दी या बाद में यह सीपीयू कैश में सिंक से बाहर हो जाएगा जैसा कि ऊपर दिए गए आरेखों में दिखाया गया है।
public class MyNonThreadSafeCode {
public int myVar = 1;
}
public class MyThreadSafeCode {
public volatile int myVar = 1;
}
अस्थिर का उपयोग करने के लाभ
तो हमें वास्तव में अपने कोड में अस्थिरता का उपयोग कब करना चाहिए? यह क्या लाभ प्रदान करता है? मैंने नीचे कुछ रेखांकित किया है:
धागे के बीच दृश्यता
जैसा कि ऊपर बताया गया है, volatile
कीवर्ड यह सुनिश्चित करता है कि अस्थिर चर में किया गया कोई भी परिवर्तन अन्य थ्रेड्स को तुरंत दिखाई देगा। यह बासी डेटा की समस्या से बचने में मदद करता है, जहाँ एक थ्रेड में एक वैरिएबल के मान की कैश्ड कॉपी हो सकती है जो सबसे अद्यतित नहीं है।
सरलीकृत मल्टीथ्रेडिंग
अस्थिर चर का उपयोग करके थ्रेड्स को ताले या अन्य तुल्यकालन तंत्र की आवश्यकता के बिना एक दूसरे के साथ संवाद करने की अनुमति देकर मल्टीथ्रेडिंग को सरल बनाया जा सकता है । यह जटिल और अक्सर त्रुटि-प्रवण लॉकिंग कोड की आवश्यकता को समाप्त कर सकता है। synchronized
मुझे यह भी लगता है कि सही तरीके से उपयोग किए जाने पर यह लॉक या ब्लॉक की तुलना में कोड को साफ और पढ़ने में आसान रखता है।
बेहतर प्रदर्शन (कुछ मामलों में)
कुछ मामलों में, अस्थिर चर का उपयोग करने से प्रदर्शन में सुधार हो सकता है क्योंकि यह तालों की आवश्यकता को कम करता है। हालांकि, गलत तरीके से उपयोग किए जाने पर वाष्पशील कीवर्ड का उपयोग वास्तव में प्रदर्शन पर नकारात्मक प्रभाव डाल सकता है। मैंने नीचे "अस्थिर कीवर्ड का उपयोग करते समय कमियां और विचार" अनुभाग में कैसे/क्यों पर चर्चा की है।
सिग्नलिंग के लिए उपयोगी
वाष्पशील चर का उपयोग थ्रेड्स के बीच एक सरल सिग्नलिंग तंत्र के रूप में किया जा सकता है। उदाहरण के लिए, एक थ्रेड अपने मान को बदलने के लिए एक अस्थिर चर की प्रतीक्षा कर सकता है, यह दर्शाता है कि किसी अन्य थ्रेड ने एक विशिष्ट कार्य पूरा कर लिया है।
वाष्पशील कीवर्ड का उपयोग करते समय कमियां और विचार
यह सब बहुत अच्छा लगता है, लेकिन volatile
चांदी की गोली नहीं है। इसका उपयोग केवल तभी किया जाना चाहिए जब आवश्यक हो और यह synchronized
आपके कोड में सिंक्रनाइज़ेशन (उदाहरण के लिए कीवर्ड के माध्यम से) के लिए प्रत्यक्ष प्रतिस्थापन नहीं है। यहाँ पर क्यों:
गलत तरीके से उपयोग किए जाने पर प्रदर्शन में कमी
क्योंकि volatile
कीवर्ड का अर्थ है कि आपका चर मान सीधे मुख्य मेमोरी से पढ़ा जाएगा, इसका प्रदर्शन पर नकारात्मक प्रभाव पड़ेगा।
इसलिए, volatile
कीवर्ड का उपयोग केवल तभी किया जाना चाहिए जब एक चर अपरिवर्तनीय नहीं है (अर्थात इसे बदला जा रहा है) और समवर्ती वातावरण में उपयोग किया जा रहा है (यानी इसे एक से अधिक थ्रेड द्वारा एक्सेस किया जाएगा) ताकि बाधा न पड़े आपके आवेदन का प्रदर्शन।
एकाधिक धागे में पढ़ने-संशोधित-लिखने के संचालन के लिए उपयुक्त नहीं है
volatile
जैसा कि आप ऊपर के उदाहरणों से देख सकते हैं, जब हम किसी वेरिएबल को एक्सेस करते हैं तो कोई लॉकिंग नहीं होती है । इसलिए, कोड को थ्रेड-सुरक्षित बनाने के अन्य तरीकों के विपरीत, जैसे कि synchronized
कीवर्ड, वाष्पशील कीवर्ड का उपयोग उन मामलों के लिए नहीं किया जाना चाहिए जहां हम "रीड-मॉडिफाई-राइट" ऑपरेशन करना चाहते हैं।
उदाहरण के लिए, यदि हमारे पास काउंटर एप्लिकेशन है, तो एक सामान्य उपयोग-मामला वृद्धि पद्धति को लागू करना होगा। यह विधि काउंटर के वर्तमान मूल्य को पढ़ेगी, वर्तमान मूल्य में 1 जोड़कर इसे संशोधित करेगी और फिर नए मूल्य को काउंटर पर वापस लिखेगी ।
इनमें से प्रत्येक ऑपरेशन एक एकल सीपीयू निर्देश/चक्र में नहीं हो सकता है। इसलिए, यह संभव है कि मूल थ्रेड के पढ़ने और लिखने के संचालन के बीच काउंटर वेरिएबल तक पहुंचकर एक और धागा हस्तक्षेप कर सकता है । इस प्रकार, काउंटर में वृद्धि को आसानी से याद किया जा सकता है।
उदाहरण के लिए
Thread 1
counter
मुख्य मेमोरी से 0 के मान को पढ़ता है
Thread 1
counter
1 के मान को संशोधित करने के लिए गणना करता है
Thread 2
counter
मुख्य मेमोरी से 0 के मान को पढ़ता है
Thread 1
counter
मुख्य मेमोरी में 1 का मान लिखता है
Thread 2
counter
1 के मान को संशोधित करने के लिए गणना करता है
Thread 2
counter
मुख्य मेमोरी में 1 का मान लिखता है
संक्षेप में, volatile
कीवर्ड केवल यह गारंटी देता है कि अस्थिर चर में कोई भी परिवर्तन अन्य थ्रेड्स को तुरंत दिखाई देगा। यह गारंटी नहीं देता है कि एक थ्रेड द्वारा किए गए परिवर्तन किसी अन्य थ्रेड द्वारा अपडेट किए गए मान को देखने से पहले पूर्ण हो जाते हैं।
दूसरी ओर, तुल्यकालन, यह सुनिश्चित करने के लिए कि एक समय में केवल एक धागा कोड के एक विशिष्ट खंड को निष्पादित कर सकता है, ताले का उपयोग करके स्मृति स्थिरता के लिए मजबूत गारंटी प्रदान करता है। यह सुनिश्चित करता है कि एक थ्रेड द्वारा किए गए कोई भी परिवर्तन किसी अन्य थ्रेड द्वारा अपडेट किए गए मान को देखने से पहले पूर्ण हो जाते हैं।
यह केवल चरों पर लागू होता है
volatile
केवल चरों पर लागू होता है, जबकिsynchronized
कीवर्ड को पूरे तरीकों और कोड के ब्लॉक पर लागू किया जा सकता है। इसलिए, यह विचार करना महत्वपूर्ण है कि कौन सी विधि आपके विशेष उपयोग-मामले के लिए सबसे अच्छा काम करती है।
इसे पढ़ने के लिए समय निकालने के लिए बहुत-बहुत धन्यवाद। उम्मीद है कि आपको यह समझने में कुछ मदद मिली होगी कि अस्थिर कीवर्ड वास्तव में कैसे काम करता है, और इसका उपयोग कब करना है।
यदि आपको यह अच्छा लगा या यह जानकारीपूर्ण लगा, तो कृपया मेरे कुछ अन्य लेख पढ़ने या माध्यम पर मेरा अनुसरण करने पर विचार करें। प्रोत्साहित करना!