मेमरी हार्डवेअर आर्किटेक्चर
आधुनिक मेमरी हार्डवेअर आर्किटेक्चर Java च्या अंतर्गत मेमरी मॉडेलपेक्षा वेगळे आहे. म्हणून, Java मॉडेल त्याच्यासोबत कसे कार्य करते हे जाणून घेण्यासाठी तुम्हाला हार्डवेअर आर्किटेक्चर समजून घेणे आवश्यक आहे. हा विभाग सामान्य मेमरी हार्डवेअर आर्किटेक्चरचे वर्णन करतो आणि पुढील विभागात Java कसे कार्य करते याचे वर्णन करतो.
आधुनिक संगणकाच्या हार्डवेअर आर्किटेक्चरचे एक सरलीकृत आकृती येथे आहे:
आधुनिक जगात, संगणकामध्ये 2 किंवा अधिक प्रोसेसर आहेत आणि हे आधीपासूनच सर्वसामान्य प्रमाण आहे. यापैकी काही प्रोसेसरमध्ये एकाधिक कोर देखील असू शकतात. अशा संगणकांवर, एकाच वेळी अनेक थ्रेड चालवणे शक्य आहे. प्रत्येक प्रोसेसर कोर कोणत्याही वेळी एक थ्रेड कार्यान्वित करण्यास सक्षम आहे. याचा अर्थ असा की कोणताही Java अॅप्लिकेशन प्रायोरी मल्टी-थ्रेडेड आहे आणि तुमच्या प्रोग्राममध्ये, प्रत्येक प्रोसेसर कोरसाठी एक थ्रेड एका वेळी चालू असू शकतो.
प्रोसेसर कोरमध्ये रजिस्टर्सचा एक संच असतो जो त्याच्या मेमरीमध्ये (कोअरच्या आत) राहतो. हे संगणकाच्या मुख्य मेमरी (RAM) मध्ये असलेल्या डेटापेक्षा नोंदणी डेटावर खूप वेगाने ऑपरेशन करते. याचे कारण असे की प्रोसेसर या नोंदणींमध्ये अधिक जलद प्रवेश करू शकतो.
प्रत्येक CPU चा स्वतःचा कॅशे स्तर देखील असू शकतो. बर्याच आधुनिक प्रोसेसरमध्ये ते आहे. प्रोसेसर त्याच्या कॅशेमध्ये मुख्य मेमरीपेक्षा खूप वेगाने प्रवेश करू शकतो, परंतु त्याच्या अंतर्गत नोंदणीइतका वेगवान नाही. कॅशे ऍक्सेस स्पीडचे मूल्य अंदाजे मुख्य मेमरी आणि अंतर्गत रजिस्टर्सच्या ऍक्सेस स्पीड दरम्यान असते.
शिवाय, प्रोसेसरमध्ये मल्टी-लेव्हल कॅशे ठेवण्याची जागा असते. परंतु जावा मेमरी मॉडेल हार्डवेअर मेमरीशी कसे संवाद साधते हे समजून घेण्यासाठी हे जाणून घेणे इतके महत्त्वाचे नाही. हे जाणून घेणे महत्त्वाचे आहे की प्रोसेसरमध्ये काही स्तर कॅशे असू शकतात.
कोणत्याही संगणकात RAM (मुख्य मेमरी क्षेत्र) देखील त्याच प्रकारे असते. सर्व कोर मुख्य मेमरीमध्ये प्रवेश करू शकतात. मुख्य मेमरी क्षेत्र सामान्यतः प्रोसेसर कोरच्या कॅशे मेमरीपेक्षा खूप मोठे असते.
या क्षणी जेव्हा प्रोसेसरला मुख्य मेमरीमध्ये प्रवेश करण्याची आवश्यकता असते, तेव्हा तो त्याचा काही भाग त्याच्या कॅशे मेमरीमध्ये वाचतो. हे कॅशेमधील काही डेटा त्याच्या अंतर्गत रजिस्टरमध्ये देखील वाचू शकते आणि नंतर त्यावर ऑपरेशन करू शकते. जेव्हा CPU ला निकाल परत मुख्य मेमरीमध्ये लिहायचा असतो, तेव्हा तो डेटा त्याच्या अंतर्गत रजिस्टरमधून कॅशेमध्ये आणि काही वेळा मुख्य मेमरीमध्ये फ्लश करेल.
जेव्हा प्रोसेसरला कॅशेमध्ये दुसरे काहीतरी संग्रहित करण्याची आवश्यकता असते तेव्हा कॅशेमध्ये संचयित केलेला डेटा सामान्यतः मुख्य मेमरीमध्ये परत केला जातो. कॅशेमध्ये त्याची मेमरी साफ करण्याची आणि त्याच वेळी डेटा लिहिण्याची क्षमता आहे. प्रोसेसरला प्रत्येक वेळी अपडेट करताना पूर्ण कॅशे वाचण्याची किंवा लिहिण्याची गरज नसते. सहसा कॅशे मेमरीच्या लहान ब्लॉक्समध्ये अद्यतनित केले जाते, त्यांना "कॅशे लाइन" म्हणतात. एक किंवा अधिक "कॅशे लाईन्स" कॅशे मेमरीमध्ये वाचल्या जाऊ शकतात आणि एक किंवा अधिक कॅशे लाईन्स परत मुख्य मेमरीमध्ये फ्लश केल्या जाऊ शकतात.
Java मेमरी मॉडेल आणि मेमरी हार्डवेअर आर्किटेक्चर एकत्र करणे
आधीच नमूद केल्याप्रमाणे, Java मेमरी मॉडेल आणि मेमरी हार्डवेअर आर्किटेक्चर वेगळे आहेत. हार्डवेअर आर्किटेक्चर थ्रेड स्टॅक आणि ढीग यांच्यात फरक करत नाही. हार्डवेअरवर, थ्रेड स्टॅक आणि HEAP (ढीग) मुख्य मेमरीमध्ये राहतात.
स्टॅक आणि थ्रेड हीप्सचे भाग कधीकधी कॅशे आणि CPU च्या अंतर्गत रजिस्टरमध्ये असू शकतात. हे आकृतीमध्ये दर्शविले आहे:
जेव्हा कॉम्प्युटरच्या मेमरीच्या वेगवेगळ्या भागात ऑब्जेक्ट्स आणि व्हेरिएबल्स साठवले जाऊ शकतात, तेव्हा काही समस्या उद्भवू शकतात. येथे दोन मुख्य आहेत:
- थ्रेडने शेअर केलेल्या व्हेरिएबल्समध्ये केलेल्या बदलांची दृश्यमानता.
- शेअर्ड व्हेरिएबल्स वाचताना, तपासताना आणि लिहिताना शर्यतीची स्थिती.
या दोन्ही समस्या खाली स्पष्ट केल्या जातील.
शेअर केलेल्या वस्तूंची दृश्यमानता
जर दोन किंवा अधिक थ्रेड्स अस्थिर घोषणा किंवा सिंक्रोनाइझेशनचा योग्य वापर न करता एखादी वस्तू सामायिक करत असतील, तर एका थ्रेडद्वारे सामायिक केलेल्या ऑब्जेक्टमधील बदल इतर थ्रेड्सना दिसणार नाहीत.
कल्पना करा की सामायिक केलेली वस्तू सुरुवातीला मुख्य मेमरीमध्ये संग्रहित केली जाते. CPU वर चालणारा थ्रेड समान CPU च्या कॅशेमध्ये सामायिक ऑब्जेक्ट वाचतो. तिथे तो वस्तूत बदल करतो. जोपर्यंत CPU चे कॅशे मुख्य मेमरीमध्ये फ्लश केले जात नाही तोपर्यंत, शेअर केलेल्या ऑब्जेक्टची सुधारित आवृत्ती इतर CPU वर चालणाऱ्या थ्रेड्सना दिसत नाही. अशा प्रकारे, प्रत्येक थ्रेडला शेअर केलेल्या ऑब्जेक्टची स्वतःची प्रत मिळू शकते, प्रत्येक प्रत वेगळ्या CPU कॅशेमध्ये असेल.
खालील आकृती या परिस्थितीची रूपरेषा स्पष्ट करते. डाव्या CPU वर चालणारा एक थ्रेड शेअर केलेल्या ऑब्जेक्टला त्याच्या कॅशेमध्ये कॉपी करतो आणि गणनेचे मूल्य 2 मध्ये बदलतो. हा बदल उजव्या CPU वर चालणार्या इतर थ्रेडसाठी अदृश्य आहे कारण मोजण्यासाठी अपडेट अद्याप मुख्य मेमरीमध्ये फ्लश केलेले नाही.
या समस्येचे निराकरण करण्यासाठी, आपण व्हेरिएबल घोषित करताना अस्थिर कीवर्ड वापरू शकता. हे सुनिश्चित करू शकते की दिलेले व्हेरिएबल थेट मुख्य मेमरीमधून वाचले जाते आणि अद्यतनित केल्यावर नेहमी मुख्य मेमरीमध्ये परत लिहिले जाते.
शर्यतीची स्थिती
जर दोन किंवा अधिक थ्रेड एकच ऑब्जेक्ट शेअर करत असतील आणि त्या शेअर केलेल्या ऑब्जेक्टमध्ये एकापेक्षा जास्त थ्रेड व्हेरिएबल्स अपडेट करत असतील, तर रेसची स्थिती उद्भवू शकते.
कल्पना करा की थ्रेड A त्याच्या प्रोसेसरच्या कॅशेमध्ये सामायिक केलेल्या ऑब्जेक्टचे काउंट व्हेरिएबल वाचतो. अशी कल्पना करा की थ्रेड बी समान गोष्ट करतो, परंतु दुसर्या प्रोसेसरच्या कॅशेमध्ये. आता थ्रेड A गणनेच्या मूल्यामध्ये 1 जोडतो आणि थ्रेड B तेच करतो. आता व्हेरिएबल दोनदा वाढले आहे - प्रत्येक प्रोसेसरच्या कॅशेमध्ये +1 द्वारे स्वतंत्रपणे.
जर ही वाढ अनुक्रमे केली गेली, तर काउंट व्हेरिएबल दुप्पट केले जाईल आणि मुख्य मेमरीमध्ये परत लिहिले जाईल (मूळ मूल्य + 2).
तथापि, योग्य सिंक्रोनाइझेशनशिवाय एकाच वेळी दोन वाढ केली गेली. कोणता थ्रेड (A किंवा B) मुख्य मेमरीमध्ये गणनाची अद्यतनित आवृत्ती लिहितो याची पर्वा न करता, दोन वाढ असूनही नवीन मूल्य मूळ मूल्यापेक्षा फक्त 1 अधिक असेल.
हे आकृती वर वर्णन केलेल्या शर्यतीच्या स्थितीच्या समस्येची घटना स्पष्ट करते:
या समस्येचे निराकरण करण्यासाठी, आपण Java समक्रमित ब्लॉक वापरू शकता. सिंक्रोनाइझ केलेला ब्लॉक कोणत्याही वेळी कोडच्या दिलेल्या गंभीर विभागात फक्त एक थ्रेड प्रविष्ट करू शकतो याची खात्री करतो.
सिंक्रोनाइझ्ड ब्लॉक्स ही हमी देतात की सिंक्रोनाइझ ब्लॉकमध्ये प्रवेश केलेले सर्व व्हेरिएबल्स मुख्य मेमरीमधून वाचले जातील आणि जेव्हा थ्रेड सिंक्रोनाइझ ब्लॉकमधून बाहेर पडेल, तेव्हा सर्व अपडेटेड व्हेरिएबल परत मुख्य मेमरीमध्ये फ्लश केले जातील, व्हेरिएबल व्होलॅटाइल घोषित केले आहे की नाही.
GO TO FULL VERSION