जावा थ्रेड्स तयार करणे. जावा थ्रेड्स: निर्मिती आणि समाप्ती

Android साठी 17.05.2019
Android साठी

जावा प्रोग्रामिंग भाषा. आणि आज आपण मल्टीथ्रेडिंगबद्दल बोलू:

  • मल्टीथ्रेडिंग म्हणजे काय;
  • त्याची अंमलबजावणी कशी करावी;
  • एक्झिक्युशन थ्रेड कसे तयार करायचे आणि थांबवायचे.

सुरुवातीला, आपल्याला वेगळे करणे आवश्यक आहे मल्टीथ्रेडिंग काय आहेआणि त्याची गरज का आहे. मी फार काळ त्याचे वर्णन करणार नाही.

मल्टीथ्रेडिंग ही प्रणालीची एकाच वेळी अनेक गणना करण्याची क्षमता आहे, ज्यामुळे या गणनेची प्रक्रिया वेगवान होते. उदाहरणार्थ, जेव्हा तुम्ही कॉम्प्युटर गेम खेळता तेव्हा तुम्हाला तुमचे पात्र विशिष्ट क्रिया करताना, इतर वर्ण, ॲनिमेशन, आवाज करताना दिसतात. सोप्या भाषेत सांगायचे तर हे सर्व वेगळे धागे आहेत.

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

    पॅकेज com.java ;

    धावण्यायोग्य {

    सार्वजनिक int i = 0 ;

    सार्वजनिक शून्य रन() (

    नवीन धागा(myMultithread).start(); //तिसऱ्या!!! पद्धतीतील थ्रेड्सच्या क्रमाचा अर्थ असा नाही की ते त्या क्रमाने कार्यान्वित केले जातात

प्रत्येक वेळी प्रोग्राम चालवताना त्याचा परिणाम वेगळा असू शकतो:

मी आधीच कोडमध्ये टिप्पणी दिल्याप्रमाणे: परिणाम नेहमी कोडमधील कॉलच्या क्रमाशी जुळत नाही. हे अनेक घटकांवर अवलंबून असते. तुम्ही थ्रेड्सचा प्राधान्यक्रम सेट करू शकता. मग प्रत्येक थ्रेडची स्वतःची प्राथमिकता असेल आणि परिणाम अधिक अंदाज लावता येईल, परंतु अनुभवावरून मी म्हणेन की हे देखील प्राधान्याने थ्रेडच्या अंमलबजावणीच्या कठोर ऑर्डरची हमी देत ​​नाही:

    पॅकेज com.java ;

    सार्वजनिक वर्ग MyMultithreadClass अवजारे धावण्यायोग्य { // Runnable वरून लागू करून आमचा मल्टी-थ्रेडेड वर्ग तयार करा

    सार्वजनिक int i = 0 ;

    सार्वजनिक शून्य रन() ( // रन पद्धत लागू करा

    // TODO स्वयं-निर्मित पद्धत स्टब

    MyMultithreadClass myMultithread = new MyMultithreadClass(); // आमच्या वर्गाचे उदाहरण तयार करा

    thread1.setPriority(1); // तुम्ही 0 ते 10 पर्यंत प्राधान्य सेट करू शकता

    thread2.setPriority(9); // आता परिणाम अधिक अंदाजे असेल

    thread3.setPriority(5);

    thread1.start();

    thread2.start();

    thread3.start();

आता मी मल्टीथ्रेडिंग तयार करण्याची दुसरी पद्धत पाहण्याचा प्रस्ताव देतो: वर्गातील वारसा. मला विश्वास आहे की तुम्हाला लेखावरून लक्षात आले आहे की जावामध्ये तुम्हाला फक्त एका वर्गाकडून वारसा मिळू शकतो. हा या पद्धतीचा तोटा आहे. तुमचा वर्ग यापुढे इतर वर्गांना वारसा मिळवू शकणार नाही:

    पॅकेज com.java ;

    सार्वजनिक वर्ग MyMultithreadClass विस्तारित आहे धागा { // आमचा मल्टी-थ्रेडेड क्लास थ्रेडमधून इनहेरिट करून तयार करा

    सार्वजनिक स्थिर इंट i = 0 ; // व्हेरिएबलला स्टॅटिकमध्ये बदलले जेणेकरुन ते क्लासला बांधील नाही.

    सार्वजनिक शून्य रन() ( // रन पद्धत लागू करा

    // TODO स्वयं-निर्मित पद्धत स्टब

    MyMultithreadClass thread1 = नवीन MyMultithreadClass();

    MyMultithreadClass thread2 = नवीन MyMultithreadClass();

    MyMultithreadClass thread3 = नवीन MyMultithreadClass();

    thread1.start();

    thread2.start();

    thread3.start();

अंमलबजावणीचा परिणाम अद्याप अंदाज करता येत नाही:

जसे आपण पाहू शकता, थ्रेड तयार करणे अजिबात कठीण नाही. त्यांचे व्यवस्थापन आणि ते वापरत असलेली संसाधने व्यवस्थापित करणे काहीसे कठीण आहे. थ्रेड्ससह कार्य करताना आपल्याला खूप सावधगिरी बाळगण्याची आवश्यकता आहे, कारण परिणाम आपल्या अपेक्षेप्रमाणे नसू शकतात.

थ्रेडची काही अवस्था असतात. त्यापैकी एकूण 4 आहेत:

  • निर्मिती (जेव्हा आम्ही नवीन धागा लिहिला();
  • start(thread1.start());
  • अंमलबजावणी (रन() पद्धत चालू असताना);
  • समाप्ती (जेव्हा थ्रेडने त्याचे कार्य केले आहे).

तुमच्यासाठी हे एक उपयुक्त चित्र आहे:

जसे आपण आकृतीमध्ये पाहतो, धागा देखील प्रतीक्षा करू शकतो. एखाद्या धाग्यावर तात्पुरते जबरदस्ती करून त्याचे काम थांबवण्याची पद्धत वर्गात आहे प्रतीक्षा करा(), जे पद्धत कॉल करेपर्यंत अंमलबजावणीला विराम देते सूचित करा(). या थ्रेड क्लासच्या पद्धती आहेत असे म्हणणे चुकीचे आहे. या ऑब्जेक्ट पद्धती आहेत. कदाचित एखाद्या दिवशी तुम्हाला चाचणी किंवा मुलाखतीत ऑब्जेक्ट क्लासच्या पद्धतींची नावे सांगण्यास सांगितले जाईल; नंतर आपण प्रतीक्षा () आणि सूचित() लक्षात ठेवलेल्या पद्धतींना सुरक्षितपणे कॉल करू शकता.

स्थिर पद्धतींमध्ये एक पद्धत आहे झोप(), जे मिलिसेकंद म्हणून पूर्णांक व्हेरिएबल घेते ज्यासाठी थ्रेडला विराम द्यावा. या पद्धतीला कोडमध्ये कुठेही कॉल केला जाऊ शकतो जेथे तुम्हाला अंमलबजावणी थांबवायची आहे किंवा कमी करायची आहे. जेव्हा मला कन्सोलमध्ये मोठ्या प्रमाणात डेटा पाहण्याची आणि मला आवश्यक असलेले शोधण्याची आवश्यकता असते तेव्हा मी ही पद्धत लूपमध्ये वापरली. होय, प्रथम, मी ते कन्सोलमध्ये डीबग केले)).

अशा प्रकारे व्हेरिएबल 500 मिलिसेकंदांच्या विलंबाने आउटपुट होईल. फक्त लक्षात ठेवा की ही पद्धत InterruptedException टाकू शकते; म्हणून, त्याला कॉल करताना, तुम्हाला एकतर ट्राय-कॅच ब्लॉकमध्ये गुंडाळणे आवश्यक आहे किंवा पद्धतीच्या नावानंतर थ्रो इंटरप्टेडएक्सेप्शन लिहावे लागेल.

दुसरी पद्धत आहे उत्पन्न(),कॉल केल्यावर, थ्रेड काही काळ काम करणे थांबवते, ज्यामुळे इतर थ्रेड्स देखील कार्यान्वित होतात.

धागे नष्ट करण्याच्या पद्धती आहेत थांबवा()आणि नष्ट करा(). त्यांच्यातील फरक असा आहे की एकदा नष्ट() कॉल केला की, थ्रेड पुन्हा सुरू करता येत नाही. आपण पद्धत कॉल करून थ्रेडच्या अंमलबजावणीमध्ये व्यत्यय आणू शकता व्यत्यय ().

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

नमस्कार! या लेखात, मी तुम्हाला जावामधील प्रक्रिया, थ्रेड्स आणि मल्टी-थ्रेडेड प्रोग्रामिंगच्या मूलभूत गोष्टींबद्दल थोडक्यात परिचय करून देईन.
मल्टीथ्रेडिंगचा सर्वात स्पष्ट अनुप्रयोग इंटरफेस प्रोग्रामिंग आहे. जेव्हा तुम्हाला GUI ने काही प्रक्रिया होत असताना वापरकर्त्याच्या इनपुटला प्रतिसाद देणे सुरू ठेवायचे असते तेव्हा मल्टीथ्रेडिंग आवश्यक असते. उदाहरणार्थ, इंटरफेससाठी जबाबदार असलेला थ्रेड इंटरनेटवरून फाईल डाउनलोड करून दुसरा थ्रेड पूर्ण होण्याची प्रतीक्षा करू शकतो आणि यावेळी काही ॲनिमेशन प्रदर्शित करू शकतो किंवा प्रगती बार अपडेट करू शकतो. याव्यतिरिक्त, जर "रद्द करा" बटण क्लिक केले असेल तर ते थ्रेडला फाइल डाउनलोड करणे थांबवू शकते.

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

आपण सुरु करू. प्रथम, प्रक्रियांबद्दल.

प्रक्रिया

प्रक्रिया म्हणजे कोड आणि डेटाचा एक संग्रह आहे जो एक सामान्य आभासी पत्ता जागा सामायिक करतो. बऱ्याचदा, एका प्रोग्राममध्ये एक प्रक्रिया असते, परंतु अपवाद आहेत (उदाहरणार्थ, क्रोम ब्राउझर प्रत्येक टॅबसाठी एक स्वतंत्र प्रक्रिया तयार करतो, ज्यामुळे त्याला काही फायदे मिळतात, जसे की टॅब एकमेकांपासून स्वतंत्र असणे). प्रक्रिया एकमेकांपासून वेगळ्या आहेत, म्हणून दुसर्या प्रक्रियेच्या मेमरीमध्ये थेट प्रवेश करणे अशक्य आहे (प्रक्रियांमधील परस्परसंवाद विशेष माध्यमांचा वापर करून केला जातो).

प्रत्येक प्रक्रियेसाठी, OS एक तथाकथित "व्हर्च्युअल ॲड्रेस स्पेस" तयार करते ज्यामध्ये प्रक्रियेला थेट प्रवेश असतो. ही जागा प्रक्रियेशी संबंधित आहे, त्यात फक्त त्याचा डेटा आहे आणि पूर्णपणे त्याच्या विल्हेवाटीवर आहे. प्रक्रियेची आभासी जागा भौतिक मेमरीमध्ये कशी मॅप केली जाते यासाठी ऑपरेटिंग सिस्टम जबाबदार आहे.

या परस्परसंवादाचा आराखडा चित्रात दर्शविला आहे. ऑपरेटिंग सिस्टम तथाकथित मेमरी पृष्ठांवर कार्य करते, जे फक्त एका निश्चित आकाराचे क्षेत्र असते. जर एखादी प्रक्रिया मेमरी संपली तर, सिस्टम भौतिक मेमरीमधून अतिरिक्त पृष्ठे त्यास वाटप करते. आभासी मेमरी पृष्ठे कोणत्याही क्रमाने भौतिक मेमरीमध्ये मॅप केली जाऊ शकतात.

जेव्हा एखादा प्रोग्राम सुरू होतो, तेव्हा ऑपरेटिंग सिस्टम एक प्रक्रिया तयार करते, प्रोग्रामचा कोड आणि डेटा त्याच्या ॲड्रेस स्पेसमध्ये लोड करते आणि नंतर तयार केलेल्या प्रक्रियेचा मुख्य थ्रेड सुरू करते.

प्रवाह

एक थ्रेड कोड अंमलबजावणीचे एक युनिट आहे. प्रत्येक थ्रेड क्रमाक्रमाने त्या प्रक्रियेतील इतर थ्रेड्सच्या समांतर, ज्या प्रक्रियेशी संबंधित आहे त्या सूचनांची अंमलबजावणी करतो.

"इतर थ्रेड्सच्या समांतर" या वाक्यांशावर स्वतंत्रपणे चर्चा केली पाहिजे. हे ज्ञात आहे की प्रत्येक प्रोसेसर कोरसाठी कोणत्याही वेळी एक एक्झिक्यूशन युनिट असते. म्हणजेच, सिंगल-कोर प्रोसेसर एका वेळी एक (सरलीकृत केसमध्ये) केवळ क्रमाने आदेशांवर प्रक्रिया करू शकतो. तथापि, सिंगल-कोर प्रोसेसर असलेल्या सिस्टमवर एकाधिक समांतर धागे चालवणे देखील शक्य आहे. या प्रकरणात, सिस्टम वेळोवेळी थ्रेड्स दरम्यान स्विच करेल, वैकल्पिकरित्या एक किंवा दुसर्या थ्रेडला कार्यान्वित करण्याची परवानगी देईल. या योजनेला स्यूडो-समांतरता म्हणतात. दुसऱ्या थ्रेडवर स्विच करण्यापूर्वी सिस्टम प्रत्येक थ्रेडची स्थिती (संदर्भ) लक्षात ठेवते आणि जेव्हा थ्रेड कार्यान्वित करण्यासाठी परत येतो तेव्हा ते पुनर्संचयित करते. थ्रेडच्या संदर्भामध्ये स्टॅक, प्रोसेसर रजिस्टर व्हॅल्यूजचा संच, अंमलात आणल्या जाणाऱ्या कमांडचा पत्ता इत्यादी पॅरामीटर्सचा समावेश असतो....

सोप्या भाषेत सांगायचे तर, छद्म-समांतर थ्रेड एक्झिक्यूशनसह, प्रोसेसर अनेक थ्रेड्स कार्यान्वित करण्याच्या दरम्यान धावतो, त्या प्रत्येकाचा काही भाग बदलून कार्यान्वित करतो.

हे असे दिसते:

आकृतीतील रंगीत चौरस प्रोसेसर सूचना आहेत (हिरव्या रंग मुख्य धाग्याच्या सूचना आहेत, निळा बाजूच्या धाग्याच्या सूचना आहेत). अंमलबजावणी डावीकडून उजवीकडे जाते. साइड थ्रेड सुरू झाल्यानंतर, त्याच्या सूचना मुख्य थ्रेडच्या सूचनांसह एकमेकांना लागू केल्या जाऊ लागतात. प्रत्येक दृष्टिकोनासाठी अंमलात आणलेल्या सूचनांची संख्या परिभाषित केलेली नाही.

समांतर थ्रेड्सच्या सूचना परस्पर मिश्रित केल्या जातात या वस्तुस्थितीमुळे काही प्रकरणांमध्ये डेटा ऍक्सेस संघर्ष होऊ शकतो. पुढील लेख थ्रेड परस्परसंवादाच्या समस्यांसाठी समर्पित असेल, परंतु आत्ता आम्ही जावामध्ये थ्रेड कसे लॉन्च केले जातात याबद्दल बोलू ...

धागे चालवत आहेत

प्रत्येक प्रक्रियेत किमान एक चालू धागा असतो. ज्या थ्रेडमधून प्रोग्रामची अंमलबजावणी सुरू होते त्याला मुख्य थ्रेड म्हणतात. Java मध्ये, प्रक्रिया तयार केल्यानंतर, मुख्य थ्रेडची अंमलबजावणी main() पद्धतीने सुरू होते. नंतर, आवश्यकतेनुसार, प्रोग्रामरद्वारे निर्दिष्ट केलेल्या ठिकाणी आणि जेव्हा त्याने निर्दिष्ट केलेल्या अटी पूर्ण केल्या जातात, तेव्हा इतर बाजूचे थ्रेड लॉन्च केले जातात.

Java मध्ये, थ्रेड क्लासच्या वंशज ऑब्जेक्ट म्हणून दर्शविला जातो. हा वर्ग मानक थ्रेडिंग यंत्रणा समाविष्ट करतो.

नवीन थ्रेड सुरू करण्याचे दोन मार्ग आहेत:

पद्धत १
थ्रेड क्लासचा एक ऑब्जेक्ट तयार करा, तो रन करण्यायोग्य इंटरफेस लागू करणारे काहीतरी कन्स्ट्रक्टरमध्ये पास करा. या इंटरफेसमध्ये run() पद्धत समाविष्ट आहे, जी नवीन थ्रेडमध्ये कार्यान्वित केली जाईल. रन() पद्धत पूर्ण झाल्यावर थ्रेड कार्यान्वित करणे पूर्ण करेल.

हे असे दिसते:

क्लास समथिंग // इंटरफेसची अंमलबजावणी करणारे काहीतरी रन करण्यायोग्य उपकरणे रन करण्यायोग्य //(रन() पद्धत समाविष्टीत आहे) ( सार्वजनिक शून्य रन() // ही पद्धत साइड थ्रेडमध्ये कार्यान्वित केली जाईल ( System.out.println("हॅलो कडून साइड थ्रेड!") ; ) ) पब्लिक क्लास प्रोग्राम // main() पद्धतीसह क्लास ( स्टॅटिक समथिंग mThing; //mThing हा क्लासचा एक ऑब्जेक्ट आहे जो रननेबल इंटरफेस पब्लिक स्टॅटिक व्हॉईड मेन (स्ट्रिंग आर्ग्स) ( mThing = new SomeThing(); थ्रेड myThready = new थ्रेड (mThing); // थ्रेड "myThready" तयार करा. System.out.println ;

कोड आणखी लहान करण्यासाठी, तुम्ही थ्रेड क्लासच्या कन्स्ट्रक्टरला रन करण्यायोग्य इंटरफेस लागू करणाऱ्या अनामित आतील वर्गाचा ऑब्जेक्ट पास करू शकता:

मुख्य() पद्धतीसह सार्वजनिक वर्ग कार्यक्रम //वर्ग. ( सार्वजनिक स्थिर शून्य मुख्य(स्ट्रिंग आर्ग्स) ( // एक थ्रेड थ्रेड तयार करा myThready = नवीन थ्रेड(नवीन रन करण्यायोग्य() ( सार्वजनिक शून्य रन() // ही पद्धत साइड थ्रेडमध्ये चालेल ( System.out.println("हॅलो बाजूच्या थ्रेडवरून) धागा!"); ) )); myThready.start(); // थ्रेड सुरू करा System.out.println("मुख्य धागा पूर्ण झाला आहे..."); ))

पद्धत 2
थ्रेड क्लासचा वंशज तयार करा आणि त्याची रन() पद्धत ओव्हरराइड करा:

क्लास AffableThread थ्रेडचा विस्तार करतो ( @Override public void run() // ही पद्धत एका बाजूच्या थ्रेडमध्ये कार्यान्वित केली जाईल ( System.out.println("साइड थ्रेडवरून नमस्कार!"); ) ) सार्वजनिक वर्ग कार्यक्रम ( स्थिर AffableThread mSecondThread; सार्वजनिक स्थिर शून्य मुख्य(स्ट्रिंग आर्ग्स) ( mSecondThread = नवीन AffableThread(); //एक थ्रेड तयार करा mSecondThread.start(); //एक थ्रेड प्रारंभ करा System.out.println("मुख्य थ्रेड संपला आहे..."); ))

वरील उदाहरणात, दुसरा थ्रेड main() पद्धतीने तयार केला जातो आणि सुरू होतो. हे लक्षात घेणे महत्त्वाचे आहे की mSecondThread.start() पद्धतीला कॉल केल्यानंतर, मुख्य थ्रेड पूर्ण होण्याची प्रतीक्षा न करता त्याची अंमलबजावणी सुरू ठेवतो. आणि start() मेथडला कॉल केल्यानंतर येणाऱ्या सूचना mSecondThread थ्रेडच्या सूचनांच्या समांतरपणे कार्यान्वित केल्या जातील.

थ्रेड्सच्या समांतर ऑपरेशनचे प्रात्यक्षिक करण्यासाठी, चला एक प्रोग्राम विचारात घेऊया ज्यामध्ये दोन धागे "प्रथम कोणते आले, अंडे की कोंबडी?" या तात्विक प्रश्नावर वाद घालतात. मुख्य धागा खात्री आहे की कोंबडी प्रथम आली आहे, जी प्रत्येक सेकंदाला कळवेल. दुसरा धागा त्याच्या प्रतिस्पर्ध्याला सेकंदातून एकदा खंडन करेल. वाद एकूण 5 सेकंद चालेल. ज्वलंत तात्विक प्रश्न या प्रश्नाचे उत्तर देणारा शेवटचा प्रवाह विजेता असेल. उदाहरणामध्ये अद्याप चर्चा झालेली नसलेली वैशिष्ट्ये वापरतात (isAlive() sleep() आणि join()). त्यांच्यावर टिप्पण्या दिल्या आहेत आणि त्यांच्याबद्दल अधिक तपशीलवार चर्चा केली जाईल.

क्लास एगव्हॉइसने थ्रेडचा विस्तार केला ( @Override public void run() ( for(int i = 0; i< 5; i++) { try{ sleep(1000); //Приостанавливает поток на 1 секунду }catch(InterruptedException e){} System.out.println("яйцо!"); } //Слово «яйцо» сказано 5 раз } } public class ChickenVoice //Класс с методом main() { static EggVoice mAnotherOpinion; //Побочный поток public static void main(String args) { mAnotherOpinion = new EggVoice(); //Создание потока System.out.println("Спор начат..."); mAnotherOpinion.start(); //Запуск потока for(int i = 0; i < 5; i++) { try{ Thread.sleep(1000); //Приостанавливает поток на 1 секунду }catch(InterruptedException e){} System.out.println("курица!"); } //Слово «курица» сказано 5 раз if(mAnotherOpinion.isAlive()) //Если оппонент еще не сказал последнее слово { try{ mAnotherOpinion.join(); //Подождать пока оппонент закончит высказываться. }catch(InterruptedException e){} System.out.println("Первым появилось яйцо!"); } else //если оппонент уже закончил высказываться { System.out.println("Первой появилась курица!"); } System.out.println("Спор закончен!"); } } Консоль: Спор начат... курица! яйцо! яйцо! курица! яйцо! курица! яйцо! курица! яйцо! курица! Первой появилась курица! Спор закончен!

वरील उदाहरणात, दोन थ्रेड्स 5 सेकंदात समांतरपणे कन्सोलवर माहिती आउटपुट करतात. कोणता धागा शेवटचे बोलणे पूर्ण करेल हे सांगता येत नाही. तुम्ही प्रयत्न करू शकता, आणि तुम्ही अंदाजही लावू शकता, पण पुढच्या वेळी तोच प्रोग्राम चालवला जाईल तेव्हा तो वेगळा “विजेता” असण्याची उच्च शक्यता आहे. हे "असिंक्रोनस कोड एक्झिक्यूशन" नावाच्या एखाद्या गोष्टीमुळे होते. असिंक्रोनी म्हणजे असे म्हणता येत नाही की एका थ्रेडची कोणतीही सूचना दुसऱ्याच्या सूचनेपेक्षा आधी किंवा नंतर अंमलात येईल. किंवा, दुसऱ्या शब्दांत, समांतर थ्रेड्स एकमेकांपासून स्वतंत्र असतात, त्याशिवाय ज्या प्रकरणांमध्ये प्रोग्रामर स्वतः थ्रेड्समधील अवलंबित्वाचे वर्णन करतो त्यासाठी भाषा साधनांचा वापर करून.

आता प्रक्रिया पूर्ण करण्याबद्दल थोडेसे...

प्रक्रिया समाप्ती आणि डिमन

Java मध्ये, शेवटचा थ्रेड संपल्यावर प्रक्रिया संपुष्टात येते. जरी main() पद्धत आधीच पूर्ण झाली असेल, परंतु ते तयार केलेले थ्रेड्स अजूनही चालू आहेत, सिस्टम त्यांची पूर्ण होण्याची प्रतीक्षा करेल.

तथापि, हा नियम विशेष प्रकारच्या धाग्यावर लागू होत नाही - डिमन. जर प्रक्रियेचा शेवटचा सामान्य थ्रेड पूर्ण झाला असेल आणि फक्त डिमन धागे उरले असतील तर ते जबरदस्तीने संपुष्टात आणले जातील आणि प्रक्रिया समाप्त होईल. बऱ्याचदा, डिमन थ्रेड्सचा वापर पार्श्वभूमी कार्ये करण्यासाठी केला जातो जे त्याच्या कार्यकाळात प्रक्रिया पूर्ण करतात.

थ्रेडला डिमन म्हणून घोषित करणे अगदी सोपे आहे - थ्रेड सुरू करण्यापूर्वी तुम्हाला त्याची पद्धत कॉल करणे आवश्यक आहे. सेटडेमन(सत्य);
तुम्ही थ्रेड डिमन आहे की नाही ते त्याची पद्धत कॉल करून तपासू शकता बुलियन isDaemon();

थ्रेड्स समाप्त करणे

थ्रेड संपुष्टात आणण्यासाठी जावामध्ये (होते) माध्यमे आहेत. विशेषतः, Thread.stop() पद्धत अंमलबजावणीनंतर लगेच थ्रेड बंद करते. तथापि, ही पद्धत, तसेच Thread.suspend(), जी थ्रेड निलंबित करते, आणि Thread.resume(), जी थ्रेडची अंमलबजावणी सुरू ठेवते, ते नापसंत केले गेले आहे आणि त्यांचा वापर आता अत्यंत निरुत्साहित आहे. वस्तुस्थिती अशी आहे की ऑपरेशन चालवताना धागा "मारला" जाऊ शकतो, ज्याच्या मध्य-वाक्यातील व्यत्यय काही ऑब्जेक्ट चुकीच्या स्थितीत सोडेल, ज्यामुळे पकडणे कठीण आणि यादृच्छिकपणे उद्भवणारी त्रुटी दिसून येईल.

थ्रेड संपुष्टात आणण्यासाठी सक्ती करण्याऐवजी, एक योजना वापरली जाते ज्यामध्ये प्रत्येक थ्रेड स्वतःच्या समाप्तीसाठी जबाबदार असतो. थ्रेड एकतर मुख्य थ्रेडसाठी रन() पद्धत (main() कार्यान्वित केल्यावर किंवा दुसऱ्या थ्रेडच्या सिग्नलद्वारे थांबू शकतो. शिवाय, अशा सिग्नलवर कशी प्रतिक्रिया द्यायची हा पुन्हा प्रवाहाचा विषय आहे. ते प्राप्त झाल्यानंतर, थ्रेड काही ऑपरेशन्स आणि पूर्ण अंमलबजावणी करू शकतो किंवा तो पूर्णपणे दुर्लक्ष करू शकतो आणि कार्यान्वित करणे सुरू ठेवू शकतो. थ्रेड टर्मिनेशन सिग्नलला प्रतिसादाचे वर्णन करणे ही प्रोग्रामरची जबाबदारी आहे.

Java मध्ये इंटरप्शन नावाची अंगभूत थ्रेड सूचना यंत्रणा आहे, जी आम्ही लवकरच पाहू, परंतु प्रथम खालील कोड पहा:

Incremenator हा एक थ्रेड आहे जो स्टॅटिक व्हेरिएबल Program.mValue च्या व्हॅल्यूमधून प्रत्येक सेकंदाला एक जोडतो किंवा वजा करतो. Incremenator मध्ये दोन खाजगी फील्ड असतात - mIsIncrement आणि mFinish. कोणती क्रिया केली जाते हे बुलियन व्हेरिएबल mIsIncrement द्वारे निर्धारित केले जाते - जर ते खरे असेल, तर एकाची बेरीज केली जाते, अन्यथा वजाबाकी केली जाते. आणि mFinish मूल्य सत्य झाल्यावर थ्रेड संपतो.

वर्ग वाढवणारा थ्रेड विस्तारित करतो (//अस्थिर कीवर्ड बद्दल - खाजगी अस्थिर बुलियन mIsIncrement = सत्याच्या खाली; खाजगी अस्थिर बुलियन mFinish = असत्य; सार्वजनिक शून्य परिवर्तनAction() // क्रिया विरुद्ध बदलते ( mIsIncrement = !mIsIncrement; ) v सार्वजनिक finish( ) // थ्रेड पूर्ण करणे सुरू करते ( mFinish = true; ) @Override public void run() ( do ( if(!mFinish) // ( if(mIsIncrement) Program.mValue++; // समाप्त करण्याची गरज तपासते //Increment else Program.mValue-; //Decrement // व्हेरिएबलचे वर्तमान मूल्य आउटपुट करा (Program.mValue + ""); अन्यथा थ्रेड रिटर्न करा ); //साइड थ्रेड ऑब्जेक्ट पब्लिक स्टॅटिक व्हॉइड मेन(स्ट्रिंग आर्ग्स) ( mInc = नवीन इन्क्रिमेनेटर(); //थ्रेड तयार करणे System.out.print("Value = "); mInc.start(); //थ्रेड सुरू करा //वृद्धीची क्रिया तीन वेळा बदला // (int i = 1; i) साठी i*2 सेकंदांच्या अंतराने<= 3; i++) { try{ Thread.sleep(i*2*1000); //Ожидание в течении i*2 сек. }catch(InterruptedException e){} mInc.changeAction(); //Переключение действия } mInc.finish(); //Инициация завершения побочного потока } } Консоль: Значение = 1 2 1 0 -1 -2 -1 0 1 2 3 4

तुम्ही ChangeAction() पद्धत (वजाबाकी जोडण्यासाठी आणि उलट बदलण्यासाठी) आणि फिनिश() पद्धत (प्रवाह संपुष्टात आणण्यासाठी) वापरून प्रवाहाशी संवाद साधू शकता.

अस्थिर कीवर्ड mIsIncrement आणि mFinish व्हेरिएबल्सच्या घोषणेमध्ये वापरले गेले. हे भिन्न थ्रेड्सद्वारे वापरल्या जाणाऱ्या चलांसाठी वापरणे आवश्यक आहे. याचे कारण असे की नॉन-व्होलॅटाइल व्हेरिएबलचे मूल्य प्रत्येक थ्रेडसाठी स्वतंत्रपणे कॅश केले जाऊ शकते आणि त्या कॅशेमधील मूल्य प्रत्येक थ्रेडसाठी भिन्न असू शकते. अस्थिर कीवर्डसह व्हेरिएबल घोषित केल्याने अशा प्रकारचे कॅशिंग अक्षम होते आणि व्हेरिएबलच्या सर्व विनंत्या थेट मेमरीमध्ये पाठवल्या जातील.

हे उदाहरण दाखवते की तुम्ही थ्रेडमधील संवाद कसे व्यवस्थित करू शकता. तथापि, थ्रेड पूर्ण करण्याच्या या दृष्टिकोनात एक समस्या आहे - इंक्रिमेनेटर mFinish फील्डचे मूल्य प्रति सेकंद एकदा तपासतो, त्यामुळे Finish() पद्धत अंमलात आणली जाते आणि प्रत्यक्षात थ्रेड दरम्यान काही सेकंदाचा कालावधी असू शकतो. समाप्त बाहेरून सिग्नल मिळाल्यावर, स्लीप() पद्धत परत केली आणि थ्रेड त्वरित संपुष्टात आला तर ते चांगले होईल. ही परिस्थिती हाताळण्यासाठी, व्यत्यय नावाचे एक अंगभूत थ्रेड सूचना साधन आहे.

व्यत्यय

थ्रेड क्लासमध्ये इंक्रिमेनेटर प्रोग्राममधील mFinish फील्ड प्रमाणेच छुपे बूलियन फील्ड आहे, ज्याला इंटरप्ट फ्लॅग म्हणतात. हा ध्वज थ्रेडच्या इंटरप्ट() पद्धतीला कॉल करून सेट केला जाऊ शकतो. हा ध्वज सेट आहे की नाही हे तपासण्याचे दोन मार्ग आहेत. पहिला मार्ग म्हणजे थ्रेड ऑब्जेक्टच्या bool isInterrupted() पद्धतीला कॉल करणे, दुसरा स्टॅटिक bool Thread.interrupted() पद्धतीला कॉल करणे. पहिली पद्धत व्यत्यय ध्वजाची स्थिती परत करते आणि ध्वज अस्पर्श ठेवते. दुसरी पद्धत ध्वजाची स्थिती परत करते आणि ती रीसेट करते. लक्षात घ्या की Thread.interrupted() ही थ्रेड क्लासची एक स्थिर पद्धत आहे आणि तिचा कॉल ज्या थ्रेडवरून कॉल केला होता त्याच्या इंटरप्ट फ्लॅगचे मूल्य परत करतो. म्हणून, ही पद्धत केवळ थ्रेडमधून कॉल केली जाते आणि थ्रेडला त्याची व्यत्यय स्थिती तपासण्याची परवानगी देते.

चला तर मग आपल्या कार्यक्रमाकडे परत जाऊया. व्यत्यय यंत्रणा आम्हाला थ्रेडच्या झोपेच्या समस्येचे निराकरण करण्यास अनुमती देईल. स्लीप(), प्रतीक्षा() आणि जॉइन() सारख्या थ्रेडच्या अंमलबजावणीला स्थगिती देणाऱ्या पद्धतींची एक खासियत आहे - जर थ्रेडची इंटरप्ट() पद्धत चालू असताना कॉल केली गेली, तर ते थ्रेडची वाट न पाहता एक InterruptedException टाकतील. कालबाह्य समाप्ती.

चला Incremenator प्रोग्राम पुन्हा काम करू - आता, Finish() पद्धत वापरून थ्रेड संपवण्याऐवजी, आपण मानक interrupt() पद्धत वापरू. आणि mFinish ध्वज तपासण्याऐवजी, आम्ही पद्धत bool Thread.interrupted();
व्यत्यय समर्थन जोडल्यानंतर वाढीव वर्ग हा कसा दिसेल:

वर्ग वाढवणारा थ्रेड वाढवतो ( खाजगी अस्थिर बुलियन mIsIncrement = सत्य; सार्वजनिक शून्य बदला () // क्रिया उलट करते ( mIsIncrement = !mIsIncrement; ) @Override public void run() ( do ( if(!Thread.interrupted()) / / व्यत्यय तपासा ( if(mIsIncrement) Program.mValue++; //Increment else Program.mValue--; //Decrement //आउटपुट व्हेरिएबलचे वर्तमान मूल्य System.out.print(Program.mValue + ""); ) अन्यथा परत करा // /थ्रेड संपवण्याचा प्रयत्न करा( Thread.sleep(1000); // 1 सेकंदासाठी धागा निलंबित करा. )catch(InterruptedException e)( परत करा; // व्यत्ययानंतर थ्रेड संपवा) ) तर(true) ) वर्ग कार्यक्रम ( //व्हेरिएबल); जो पब्लिक स्टॅटिक इंक्रिमेनेटर mInc; //साइड थ्रेड ऑब्जेक्ट पब्लिक स्टॅटिक व्हॉइड मेन (mInc = new Incremenator) वर चालतो; //थ्रेड सिस्टम तयार करणे out.print("व्हॅल्यू = "); //थ्रेड सुरू करा // i*2 सेकंदांच्या अंतराने (int i = 1; i<= 3; i++) { try{ Thread.sleep(i*2*1000); //Ожидание в течении i*2 сек. }catch(InterruptedException e){} mInc.changeAction(); //Переключение действия } mInc.interrupt(); //Прерывание побочного потока } } Консоль: Значение = 1 2 1 0 -1 -2 -1 0 1 2 3 4

तुम्ही बघू शकता, आम्ही फिनिश() पद्धतीपासून मुक्त झालो आणि बिल्ट-इन इंटरप्ट सिस्टम वापरून समान थ्रेड टर्मिनेशन यंत्रणा लागू केली. या अंमलबजावणीमध्ये, आम्हाला एक फायदा आहे - स्लीप() पद्धत थ्रेडमध्ये व्यत्यय आणल्यानंतर लगेच नियंत्रण (अपवाद टाका) परत करेल.

लक्षात घ्या की sleep() आणि join() पद्धती ट्राय-कॅच कन्स्ट्रक्टमध्ये गुंडाळल्या आहेत. या पद्धती कार्य करण्यासाठी ही एक आवश्यक अट आहे. त्यांना कॉल करणाऱ्या कोडने प्रतीक्षा करताना व्यत्यय आल्यावर टाकलेला InterruptedException पकडला पाहिजे.

आम्ही थ्रेड्सची सुरुवात आणि शेवटची क्रमवारी लावली आहे, त्यानंतर मी थ्रेड्ससह काम करताना वापरल्या जाणाऱ्या पद्धतींबद्दल बोलेन.

Thread.sleep() पद्धत

Thread.sleep() ही थ्रेड क्लासची एक स्थिर पद्धत आहे जी ज्या थ्रेडवर कॉल केली होती त्याची अंमलबजावणी स्थगित करते. स्लीप() पद्धत चालू असताना, सिस्टम थ्रेडला प्रोसेसर वेळ वाटप करणे थांबवते, ते इतर थ्रेड्समध्ये वितरित करते. स्लीप() पद्धत एकतर निर्दिष्ट वेळेसाठी (मिलीसेकंद किंवा नॅनोसेकंद) किंवा व्यत्ययाने थांबेपर्यंत कार्यान्वित करू शकते (अशा परिस्थितीत ती व्यत्यय आणेल).

Thread.sleep(1500); // दीड सेकंद प्रतीक्षा करते Thread.sleep(2000, 100); //2 सेकंद आणि 100 नॅनोसेकंद प्रतीक्षा करते

स्लीप() पद्धतीला प्रतीक्षा करण्यासाठी नॅनोसेकंद लागू शकतात, तरीही ते हलके घेतले जाऊ नये. बऱ्याच प्रणालींमध्ये, प्रतीक्षा वेळ अजूनही मिलीसेकंद किंवा दहापटांपर्यंत पूर्ण केला जातो.

yild() पद्धत

स्टॅटिक Thread.yield() पद्धतीमुळे प्रोसेसर सिस्टमवरील इतर थ्रेड्सवर प्रक्रिया करण्यासाठी स्विच करतो. पद्धत उपयुक्त ठरू शकते, उदाहरणार्थ, जेव्हा एखादा थ्रेड घटना घडण्याची वाट पाहत असतो आणि शक्य तितक्या वेळा त्याची घटना तपासणे आवश्यक असते. या प्रकरणात, तुम्ही इव्हेंट चेक आणि Thread.yield() पद्धत लूपमध्ये ठेवू शकता:

//संदेश येण्याची प्रतीक्षा करत असताना(!msgQueue.hasMessages()) // रांगेत कोणतेही संदेश नसताना ( Thread.yield(); // इतर थ्रेडवर नियंत्रण हस्तांतरित करा)

join() पद्धत

जावा एका थ्रेडला दुसऱ्या थ्रेडची अंमलबजावणी पूर्ण होईपर्यंत प्रतीक्षा करण्याची परवानगी देणारी यंत्रणा प्रदान करते. यासाठी join() पद्धत वापरली जाते. उदाहरणार्थ, मुख्य थ्रेडला साइड थ्रेड myThready पूर्ण होण्याची प्रतीक्षा करण्यासाठी, तुम्हाला मुख्य थ्रेडवर myThready.join() स्टेटमेंट जारी करणे आवश्यक आहे. एकदा myThready बाहेर पडल्यानंतर, join() पद्धत परत येते आणि मुख्य थ्रेड कार्यान्वित करणे सुरू ठेवू शकतो.

join() पद्धतीमध्ये ओव्हरलोड आहे जे पॅरामीटर म्हणून कालबाह्य होते. या प्रकरणात, join() थ्रेड पूर्ण होण्याची वाट पाहत असताना किंवा कालबाह्य झाल्यावर परत येतो. Thread.sleep() पद्धतीप्रमाणे, जॉइन पद्धत मिलिसेकंद आणि नॅनोसेकंदची प्रतीक्षा करू शकते - वितर्क समान आहेत.

थ्रेडची कालबाह्यता सेट करून, तुम्ही, उदाहरणार्थ, मुख्य (किंवा इतर कोणताही) थ्रेड संसाधन-केंद्रित ऑपरेशन्स पूर्ण करण्यासाठी साइड थ्रेडची प्रतीक्षा करत असताना ॲनिमेटेड प्रतिमा अद्यतनित करू शकता:

विचारवंत मेंदू = नवीन विचारक (); //विचारक हा थ्रेड वर्गाचा वंशज आहे. brain.start(); // "विचार" सुरू करा. do ( mThinkIndicator.refresh(); //mThinkIndicator - ॲनिमेटेड चित्र. प्रयत्न करा( brain.join(250); //विचार पूर्ण होण्यासाठी एक चतुर्थांश सेकंद प्रतीक्षा करा. ) पकडा(InterruptedException e)() ) असताना(मेंदू .जिवंत आहे()); //मेंदू विचार करत असताना... //मेंदूने विचार पूर्ण केला आहे (टाळ्या आहेत).

या उदाहरणात, मेंदूचा धागा एखाद्या गोष्टीबद्दल विचार करत आहे आणि असे करण्यास बराच वेळ लागेल अशी अपेक्षा आहे. मुख्य थ्रेड एक चतुर्थांश सेकंदासाठी त्याची वाट पाहतो आणि विचार करण्यासाठी ही वेळ पुरेशी नसल्यास, "विचार निर्देशक" (काही ॲनिमेटेड चित्र) अद्यतनित करतो. परिणामी, विचार करत असताना, वापरकर्ता स्क्रीनवर विचार प्रक्रियेचे एक सूचक पाहतो, ज्यामुळे त्याला कळते की इलेक्ट्रॉनिक मेंदू कशात तरी व्यस्त आहेत.

थ्रेड प्राधान्यक्रम

सिस्टममधील प्रत्येक थ्रेडचे स्वतःचे प्राधान्य असते. प्राधान्य म्हणजे थ्रेड ऑब्जेक्टमधील काही संख्या, ज्याचे उच्च मूल्य म्हणजे उच्च प्राधान्य. सिस्टम प्रथम उच्च प्राधान्य थ्रेड्स कार्यान्वित करते आणि कमी प्राधान्य थ्रेड्सना CPU वेळ फक्त तेव्हाच प्राप्त होतो जेव्हा त्यांचे अधिक विशेषाधिकार असलेले समकक्ष निष्क्रिय असतात.

तुम्ही दोन फंक्शन्स वापरून थ्रेड प्राधान्यांसह कार्य करू शकता:

व्हॉइड सेट प्रायोरिटी (इंट प्रायॉरिटी)- थ्रेडचे प्राधान्य सेट करते.
संभाव्य प्राधान्य मूल्ये MIN_PRIORITY, NORM_PRIORITY आणि MAX_PRIORITY आहेत.

int getPriority()- थ्रेडला प्राधान्य मिळते.

थ्रेड क्लासच्या काही उपयुक्त पद्धती

व्यावहारिकदृष्ट्या एवढेच. शेवटी, प्रवाहांसह कार्य करण्यासाठी येथे काही उपयुक्त पद्धती आहेत.

बुलियन isAlive()- myThready() चालू असल्यास खरे आणि थ्रेड अद्याप सुरू झाला नसल्यास किंवा संपुष्टात आल्यास असत्य परत करतो.

setName(स्ट्रिंग थ्रेडनेम)- प्रवाहाचे नाव निर्दिष्ट करते.
स्ट्रिंग getName()- थ्रेडचे नाव मिळते.
थ्रेडचे नाव त्याच्याशी संबंधित एक स्ट्रिंग आहे, जे काही प्रकरणांमध्ये कोणता थ्रेड क्रिया करत आहे हे समजण्यास मदत करते. कधीकधी हे उपयुक्त ठरू शकते.

स्थिर थ्रेड Thread.currentThread()- एक स्थिर पद्धत जी थ्रेडचा ऑब्जेक्ट परत करते ज्यामध्ये तो कॉल केला होता.

लांब getId()- थ्रेड आयडेंटिफायर परत करतो. अभिज्ञापक हा प्रवाहाला नियुक्त केलेला एक अद्वितीय क्रमांक आहे.

निष्कर्ष

मी लक्षात घेतो की लेख मल्टीथ्रेडेड प्रोग्रामिंगच्या सर्व सूक्ष्म गोष्टींबद्दल बोलत नाही. आणि उदाहरणांमध्ये दिलेल्या कोडमध्ये पूर्णपणे बरोबर असण्यासाठी काही बारकावे नाहीत. विशेषतः, उदाहरणे सिंक्रोनाइझेशन वापरत नाहीत. थ्रेड सिंक्रोनाइझेशन हा एक विषय आहे ज्याशिवाय तुम्ही योग्य मल्टी-थ्रेडेड ॲप्लिकेशन्स प्रोग्राम करू शकणार नाही. आपण याबद्दल वाचू शकता, उदाहरणार्थ, "जावा कॉन्करन्सी इन प्रॅक्टिस" किंवा पुस्तकात

शेवटचे अपडेट: 04/27/2018

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

धागा वर्ग

Java मध्ये, एकाच थ्रेडची कार्यक्षमता थ्रेड क्लासमध्ये असते. आणि नवीन धागा तयार करण्यासाठी, आपल्याला या वर्गाचा एक ऑब्जेक्ट तयार करणे आवश्यक आहे. परंतु सर्व धागे स्वतः तयार केलेले नाहीत. जेव्हा एखादा प्रोग्राम सुरू होतो तेव्हा त्या प्रोग्रामचा मुख्य धागा चालू होतो. इतर सर्व चाइल्ड थ्रेड्स या मुख्य थ्रेडमधून तयार केले जातात.

Thread.currentThread() ही स्टॅटिक पद्धत वापरून आपण सध्याच्या अंमलबजावणीचा थ्रेड मिळवू शकतो:

सार्वजनिक स्थिर शून्य मुख्य(स्ट्रिंग आर्ग्स) ( थ्रेड t = Thread.currentThread(); // मुख्य थ्रेड मिळवा System.out.println(t.getName()); // main )

डीफॉल्टनुसार, मुख्य थ्रेडचे नाव मुख्य असेल.

थ्रेड वर्ग थ्रेड नियंत्रित करण्यासाठी इतर अनेक पद्धती प्रदान करतो. सर्वात जास्त वापरलेले आहेत:

    getName(): थ्रेडचे नाव परत करते

    setName(स्ट्रिंग नाव): थ्रेडचे नाव सेट करते

    getPriority(): थ्रेड प्रायॉरिटी परत करते

    setPriority(int proirity): थ्रेडचा प्राधान्यक्रम सेट करते. कार्यान्वित करण्यासाठी थ्रेड्सच्या गुच्छातून थ्रेड निवडण्यासाठी सिस्टमसाठी प्राधान्य हा एक प्रमुख घटक आहे. अंकीय प्राधान्य मूल्य या पद्धतीमध्ये पॅरामीटर म्हणून पास केले जाते - 1 ते 10 पर्यंत. डीफॉल्टनुसार, मुख्य थ्रेड मध्यम प्राधान्य - 5 वर सेट केला जातो.

    isAlive() : थ्रेड सक्रिय असल्यास खरे मिळवते

    isInterrupted() : थ्रेडमध्ये व्यत्यय आल्यास खरे परत येते

    join(): थ्रेड संपुष्टात येण्याची वाट पाहत आहे

    run() : थ्रेडचा एंट्री पॉइंट परिभाषित करतो

    sleep() : मिलिसेकंदांच्या निर्दिष्ट संख्येसाठी थ्रेडला विराम देते

    start(): रन() मेथड कॉल करून थ्रेड सुरू करतो

आम्ही प्रवाहाविषयी सर्व माहिती प्रदर्शित करू शकतो:

सार्वजनिक स्थिर शून्य मुख्य (स्ट्रिंग आर्ग्स) ( थ्रेड t = Thread.currentThread(); // मुख्य थ्रेड मिळवा System.out.println(t); // मुख्य )

कन्सोल आउटपुट:

धागा

पहिला मुख्य थ्रेडचे नाव दर्शवेल (जे t.getName() द्वारे मिळू शकते), दुसरे मूल्य 5 थ्रेडचे प्राधान्य प्रदान करते (t.getPriority() द्वारे देखील मिळवता येते), आणि शेवटचे मुख्य थ्रेड गटाचे नाव दर्शवेल ज्याचा सध्याचा एक मुख्य देखील आहे (t.getThreadGroup().getName() द्वारे देखील मिळू शकतो.

थ्रेड्स वापरण्याचे तोटे

पुढे आपण थ्रेड कसे बनवायचे आणि कसे वापरायचे ते पाहू. हे खूपच सोपे आहे. तथापि, मल्टी-थ्रेडेड ॲप्लिकेशन तयार करताना, ॲप्लिकेशनच्या ऑपरेशनवर नकारात्मक परिणाम करू शकतील अशा अनेक परिस्थिती आम्ही विचारात घेतल्या पाहिजेत.

काही प्लॅटफॉर्मवर, नवीन थ्रेड सुरू केल्याने तुमचा अर्ज कमी होऊ शकतो. जर अनुप्रयोगाची कामगिरी आमच्यासाठी गंभीर असेल तर ते खूप महत्वाचे असू शकते.

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

नमस्कार! या लेखात, मी तुम्हाला जावामधील प्रक्रिया, थ्रेड्स आणि मल्टी-थ्रेडेड प्रोग्रामिंगच्या मूलभूत गोष्टींबद्दल थोडक्यात परिचय करून देईन.
मल्टीथ्रेडिंगचा सर्वात स्पष्ट अनुप्रयोग इंटरफेस प्रोग्रामिंग आहे. जेव्हा तुम्हाला GUI ने काही प्रक्रिया होत असताना वापरकर्त्याच्या इनपुटला प्रतिसाद देणे सुरू ठेवायचे असते तेव्हा मल्टीथ्रेडिंग आवश्यक असते. उदाहरणार्थ, इंटरफेससाठी जबाबदार असलेला थ्रेड इंटरनेटवरून फाईल डाउनलोड करून दुसरा थ्रेड पूर्ण होण्याची प्रतीक्षा करू शकतो आणि यावेळी काही ॲनिमेशन प्रदर्शित करू शकतो किंवा प्रगती बार अपडेट करू शकतो. याव्यतिरिक्त, जर "रद्द करा" बटण क्लिक केले असेल तर ते थ्रेडला फाइल डाउनलोड करणे थांबवू शकते.

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

आपण सुरु करू. प्रथम, प्रक्रियांबद्दल.

प्रक्रिया

प्रक्रिया म्हणजे कोड आणि डेटाचा एक संग्रह आहे जो एक सामान्य आभासी पत्ता जागा सामायिक करतो. बऱ्याचदा, एका प्रोग्राममध्ये एक प्रक्रिया असते, परंतु अपवाद आहेत (उदाहरणार्थ, क्रोम ब्राउझर प्रत्येक टॅबसाठी एक स्वतंत्र प्रक्रिया तयार करतो, ज्यामुळे त्याला काही फायदे मिळतात, जसे की टॅब एकमेकांपासून स्वतंत्र असणे). प्रक्रिया एकमेकांपासून वेगळ्या आहेत, म्हणून दुसर्या प्रक्रियेच्या मेमरीमध्ये थेट प्रवेश करणे अशक्य आहे (प्रक्रियांमधील परस्परसंवाद विशेष माध्यमांचा वापर करून केला जातो).

प्रत्येक प्रक्रियेसाठी, OS एक तथाकथित "व्हर्च्युअल ॲड्रेस स्पेस" तयार करते ज्यामध्ये प्रक्रियेला थेट प्रवेश असतो. ही जागा प्रक्रियेशी संबंधित आहे, त्यात फक्त त्याचा डेटा आहे आणि पूर्णपणे त्याच्या विल्हेवाटीवर आहे. प्रक्रियेची आभासी जागा भौतिक मेमरीमध्ये कशी मॅप केली जाते यासाठी ऑपरेटिंग सिस्टम जबाबदार आहे.

या परस्परसंवादाचा आराखडा चित्रात दर्शविला आहे. ऑपरेटिंग सिस्टम तथाकथित मेमरी पृष्ठांवर कार्य करते, जे फक्त एका निश्चित आकाराचे क्षेत्र असते. जर एखादी प्रक्रिया मेमरी संपली तर, सिस्टम भौतिक मेमरीमधून अतिरिक्त पृष्ठे त्यास वाटप करते. आभासी मेमरी पृष्ठे कोणत्याही क्रमाने भौतिक मेमरीमध्ये मॅप केली जाऊ शकतात.

जेव्हा एखादा प्रोग्राम सुरू होतो, तेव्हा ऑपरेटिंग सिस्टम एक प्रक्रिया तयार करते, प्रोग्रामचा कोड आणि डेटा त्याच्या ॲड्रेस स्पेसमध्ये लोड करते आणि नंतर तयार केलेल्या प्रक्रियेचा मुख्य थ्रेड सुरू करते.

प्रवाह

एक थ्रेड कोड अंमलबजावणीचे एक युनिट आहे. प्रत्येक थ्रेड क्रमाक्रमाने त्या प्रक्रियेतील इतर थ्रेड्सच्या समांतर, ज्या प्रक्रियेशी संबंधित आहे त्या सूचनांची अंमलबजावणी करतो.

"इतर थ्रेड्सच्या समांतर" या वाक्यांशावर स्वतंत्रपणे चर्चा केली पाहिजे. हे ज्ञात आहे की प्रत्येक प्रोसेसर कोरसाठी कोणत्याही वेळी एक एक्झिक्यूशन युनिट असते. म्हणजेच, सिंगल-कोर प्रोसेसर एका वेळी एक (सरलीकृत केसमध्ये) केवळ क्रमाने आदेशांवर प्रक्रिया करू शकतो. तथापि, सिंगल-कोर प्रोसेसर असलेल्या सिस्टमवर एकाधिक समांतर धागे चालवणे देखील शक्य आहे. या प्रकरणात, सिस्टम वेळोवेळी थ्रेड्स दरम्यान स्विच करेल, वैकल्पिकरित्या एक किंवा दुसर्या थ्रेडला कार्यान्वित करण्याची परवानगी देईल. या योजनेला स्यूडो-समांतरता म्हणतात. दुसऱ्या थ्रेडवर स्विच करण्यापूर्वी सिस्टम प्रत्येक थ्रेडची स्थिती (संदर्भ) लक्षात ठेवते आणि जेव्हा थ्रेड कार्यान्वित करण्यासाठी परत येतो तेव्हा ते पुनर्संचयित करते. थ्रेडच्या संदर्भामध्ये स्टॅक, प्रोसेसर रजिस्टर व्हॅल्यूजचा संच, अंमलात आणल्या जाणाऱ्या कमांडचा पत्ता इत्यादी पॅरामीटर्सचा समावेश असतो....

सोप्या भाषेत सांगायचे तर, छद्म-समांतर थ्रेड एक्झिक्यूशनसह, प्रोसेसर अनेक थ्रेड्स कार्यान्वित करण्याच्या दरम्यान धावतो, त्या प्रत्येकाचा काही भाग बदलून कार्यान्वित करतो.

हे असे दिसते:

आकृतीतील रंगीत चौरस प्रोसेसर सूचना आहेत (हिरव्या रंग मुख्य धाग्याच्या सूचना आहेत, निळा बाजूच्या धाग्याच्या सूचना आहेत). अंमलबजावणी डावीकडून उजवीकडे जाते. साइड थ्रेड सुरू झाल्यानंतर, त्याच्या सूचना मुख्य थ्रेडच्या सूचनांसह एकमेकांना लागू केल्या जाऊ लागतात. प्रत्येक दृष्टिकोनासाठी अंमलात आणलेल्या सूचनांची संख्या परिभाषित केलेली नाही.

समांतर थ्रेड्सच्या सूचना परस्पर मिश्रित केल्या जातात या वस्तुस्थितीमुळे काही प्रकरणांमध्ये डेटा ऍक्सेस संघर्ष होऊ शकतो. पुढील लेख थ्रेड परस्परसंवादाच्या समस्यांसाठी समर्पित असेल, परंतु आत्ता आम्ही जावामध्ये थ्रेड कसे लॉन्च केले जातात याबद्दल बोलू ...

धागे चालवत आहेत

प्रत्येक प्रक्रियेत किमान एक चालू धागा असतो. ज्या थ्रेडमधून प्रोग्रामची अंमलबजावणी सुरू होते त्याला मुख्य थ्रेड म्हणतात. Java मध्ये, प्रक्रिया तयार केल्यानंतर, मुख्य थ्रेडची अंमलबजावणी main() पद्धतीने सुरू होते. नंतर, आवश्यकतेनुसार, प्रोग्रामरद्वारे निर्दिष्ट केलेल्या ठिकाणी आणि जेव्हा त्याने निर्दिष्ट केलेल्या अटी पूर्ण केल्या जातात, तेव्हा इतर बाजूचे थ्रेड लॉन्च केले जातात.

Java मध्ये, थ्रेड क्लासच्या वंशज ऑब्जेक्ट म्हणून दर्शविला जातो. हा वर्ग मानक थ्रेडिंग यंत्रणा समाविष्ट करतो.

नवीन थ्रेड सुरू करण्याचे दोन मार्ग आहेत:

पद्धत १
थ्रेड क्लासचा एक ऑब्जेक्ट तयार करा, तो रन करण्यायोग्य इंटरफेस लागू करणारे काहीतरी कन्स्ट्रक्टरमध्ये पास करा. या इंटरफेसमध्ये run() पद्धत समाविष्ट आहे, जी नवीन थ्रेडमध्ये कार्यान्वित केली जाईल. रन() पद्धत पूर्ण झाल्यावर थ्रेड कार्यान्वित करणे पूर्ण करेल.

हे असे दिसते:

क्लास समथिंग // इंटरफेसची अंमलबजावणी करणारे काहीतरी रन करण्यायोग्य उपकरणे रन करण्यायोग्य //(रन() पद्धत समाविष्टीत आहे) ( सार्वजनिक शून्य रन() // ही पद्धत साइड थ्रेडमध्ये कार्यान्वित केली जाईल ( System.out.println("हॅलो कडून साइड थ्रेड!") ; ) ) पब्लिक क्लास प्रोग्राम // main() पद्धतीसह क्लास ( स्टॅटिक समथिंग mThing; //mThing हा क्लासचा एक ऑब्जेक्ट आहे जो रननेबल इंटरफेस पब्लिक स्टॅटिक व्हॉईड मेन (स्ट्रिंग आर्ग्स) ( mThing = new SomeThing(); थ्रेड myThready = new थ्रेड (mThing); // थ्रेड "myThready" तयार करा. System.out.println ;

कोड आणखी लहान करण्यासाठी, तुम्ही थ्रेड क्लासच्या कन्स्ट्रक्टरला रन करण्यायोग्य इंटरफेस लागू करणाऱ्या अनामित आतील वर्गाचा ऑब्जेक्ट पास करू शकता:

मुख्य() पद्धतीसह सार्वजनिक वर्ग कार्यक्रम //वर्ग. ( सार्वजनिक स्थिर शून्य मुख्य(स्ट्रिंग आर्ग्स) ( // एक थ्रेड थ्रेड तयार करा myThready = नवीन थ्रेड(नवीन रन करण्यायोग्य() ( सार्वजनिक शून्य रन() // ही पद्धत साइड थ्रेडमध्ये चालेल ( System.out.println("हॅलो बाजूच्या थ्रेडवरून) धागा!"); ) )); myThready.start(); // थ्रेड सुरू करा System.out.println("मुख्य धागा पूर्ण झाला आहे..."); ))

पद्धत 2
थ्रेड क्लासचा वंशज तयार करा आणि त्याची रन() पद्धत ओव्हरराइड करा:

क्लास AffableThread थ्रेडचा विस्तार करतो ( @Override public void run() // ही पद्धत एका बाजूच्या थ्रेडमध्ये कार्यान्वित केली जाईल ( System.out.println("साइड थ्रेडवरून नमस्कार!"); ) ) सार्वजनिक वर्ग कार्यक्रम ( स्थिर AffableThread mSecondThread; सार्वजनिक स्थिर शून्य मुख्य(स्ट्रिंग आर्ग्स) ( mSecondThread = नवीन AffableThread(); //एक थ्रेड तयार करा mSecondThread.start(); //एक थ्रेड प्रारंभ करा System.out.println("मुख्य थ्रेड संपला आहे..."); ))

वरील उदाहरणात, दुसरा थ्रेड main() पद्धतीने तयार केला जातो आणि सुरू होतो. हे लक्षात घेणे महत्त्वाचे आहे की mSecondThread.start() पद्धतीला कॉल केल्यानंतर, मुख्य थ्रेड पूर्ण होण्याची प्रतीक्षा न करता त्याची अंमलबजावणी सुरू ठेवतो. आणि start() मेथडला कॉल केल्यानंतर येणाऱ्या सूचना mSecondThread थ्रेडच्या सूचनांच्या समांतरपणे कार्यान्वित केल्या जातील.

थ्रेड्सच्या समांतर ऑपरेशनचे प्रात्यक्षिक करण्यासाठी, चला एक प्रोग्राम विचारात घेऊया ज्यामध्ये दोन धागे "प्रथम कोणते आले, अंडे की कोंबडी?" या तात्विक प्रश्नावर वाद घालतात. मुख्य धागा खात्री आहे की कोंबडी प्रथम आली आहे, जी प्रत्येक सेकंदाला कळवेल. दुसरा धागा त्याच्या प्रतिस्पर्ध्याला सेकंदातून एकदा खंडन करेल. वाद एकूण 5 सेकंद चालेल. ज्वलंत तात्विक प्रश्न या प्रश्नाचे उत्तर देणारा शेवटचा प्रवाह विजेता असेल. उदाहरणामध्ये अद्याप चर्चा झालेली नसलेली वैशिष्ट्ये वापरतात (isAlive() sleep() आणि join()). त्यांच्यावर टिप्पण्या दिल्या आहेत आणि त्यांच्याबद्दल अधिक तपशीलवार चर्चा केली जाईल.

क्लास एगव्हॉइसने थ्रेडचा विस्तार केला ( @Override public void run() ( for(int i = 0; i< 5; i++) { try{ sleep(1000); //Приостанавливает поток на 1 секунду }catch(InterruptedException e){} System.out.println("яйцо!"); } //Слово «яйцо» сказано 5 раз } } public class ChickenVoice //Класс с методом main() { static EggVoice mAnotherOpinion; //Побочный поток public static void main(String args) { mAnotherOpinion = new EggVoice(); //Создание потока System.out.println("Спор начат..."); mAnotherOpinion.start(); //Запуск потока for(int i = 0; i < 5; i++) { try{ Thread.sleep(1000); //Приостанавливает поток на 1 секунду }catch(InterruptedException e){} System.out.println("курица!"); } //Слово «курица» сказано 5 раз if(mAnotherOpinion.isAlive()) //Если оппонент еще не сказал последнее слово { try{ mAnotherOpinion.join(); //Подождать пока оппонент закончит высказываться. }catch(InterruptedException e){} System.out.println("Первым появилось яйцо!"); } else //если оппонент уже закончил высказываться { System.out.println("Первой появилась курица!"); } System.out.println("Спор закончен!"); } } Консоль: Спор начат... курица! яйцо! яйцо! курица! яйцо! курица! яйцо! курица! яйцо! курица! Первой появилась курица! Спор закончен!

वरील उदाहरणात, दोन थ्रेड्स 5 सेकंदात समांतरपणे कन्सोलवर माहिती आउटपुट करतात. कोणता धागा शेवटचे बोलणे पूर्ण करेल हे सांगता येत नाही. तुम्ही प्रयत्न करू शकता, आणि तुम्ही अंदाजही लावू शकता, पण पुढच्या वेळी तोच प्रोग्राम चालवला जाईल तेव्हा तो वेगळा “विजेता” असण्याची उच्च शक्यता आहे. हे "असिंक्रोनस कोड एक्झिक्यूशन" नावाच्या एखाद्या गोष्टीमुळे होते. असिंक्रोनी म्हणजे असे म्हणता येत नाही की एका थ्रेडची कोणतीही सूचना दुसऱ्याच्या सूचनेपेक्षा आधी किंवा नंतर अंमलात येईल. किंवा, दुसऱ्या शब्दांत, समांतर थ्रेड्स एकमेकांपासून स्वतंत्र असतात, त्याशिवाय ज्या प्रकरणांमध्ये प्रोग्रामर स्वतः थ्रेड्समधील अवलंबित्वाचे वर्णन करतो त्यासाठी भाषा साधनांचा वापर करून.

आता प्रक्रिया पूर्ण करण्याबद्दल थोडेसे...

प्रक्रिया समाप्ती आणि डिमन

Java मध्ये, शेवटचा थ्रेड संपल्यावर प्रक्रिया संपुष्टात येते. जरी main() पद्धत आधीच पूर्ण झाली असेल, परंतु ते तयार केलेले थ्रेड्स अजूनही चालू आहेत, सिस्टम त्यांची पूर्ण होण्याची प्रतीक्षा करेल.

तथापि, हा नियम विशेष प्रकारच्या धाग्यावर लागू होत नाही - डिमन. जर प्रक्रियेचा शेवटचा सामान्य थ्रेड पूर्ण झाला असेल आणि फक्त डिमन धागे उरले असतील तर ते जबरदस्तीने संपुष्टात आणले जातील आणि प्रक्रिया समाप्त होईल. बऱ्याचदा, डिमन थ्रेड्सचा वापर पार्श्वभूमी कार्ये करण्यासाठी केला जातो जे त्याच्या कार्यकाळात प्रक्रिया पूर्ण करतात.

थ्रेडला डिमन म्हणून घोषित करणे अगदी सोपे आहे - थ्रेड सुरू करण्यापूर्वी तुम्हाला त्याची पद्धत कॉल करणे आवश्यक आहे. सेटडेमन(सत्य);
तुम्ही थ्रेड डिमन आहे की नाही ते त्याची पद्धत कॉल करून तपासू शकता बुलियन isDaemon();

थ्रेड्स समाप्त करणे

थ्रेड संपुष्टात आणण्यासाठी जावामध्ये (होते) माध्यमे आहेत. विशेषतः, Thread.stop() पद्धत अंमलबजावणीनंतर लगेच थ्रेड बंद करते. तथापि, ही पद्धत, तसेच Thread.suspend(), जी थ्रेड निलंबित करते, आणि Thread.resume(), जी थ्रेडची अंमलबजावणी सुरू ठेवते, ते नापसंत केले गेले आहे आणि त्यांचा वापर आता अत्यंत निरुत्साहित आहे. वस्तुस्थिती अशी आहे की ऑपरेशन चालवताना धागा "मारला" जाऊ शकतो, ज्याच्या मध्य-वाक्यातील व्यत्यय काही ऑब्जेक्ट चुकीच्या स्थितीत सोडेल, ज्यामुळे पकडणे कठीण आणि यादृच्छिकपणे उद्भवणारी त्रुटी दिसून येईल.

थ्रेड संपुष्टात आणण्यासाठी सक्ती करण्याऐवजी, एक योजना वापरली जाते ज्यामध्ये प्रत्येक थ्रेड स्वतःच्या समाप्तीसाठी जबाबदार असतो. थ्रेड एकतर मुख्य थ्रेडसाठी रन() पद्धत (main() कार्यान्वित केल्यावर किंवा दुसऱ्या थ्रेडच्या सिग्नलद्वारे थांबू शकतो. शिवाय, अशा सिग्नलवर कशी प्रतिक्रिया द्यायची हा पुन्हा प्रवाहाचा विषय आहे. ते प्राप्त झाल्यानंतर, थ्रेड काही ऑपरेशन्स आणि पूर्ण अंमलबजावणी करू शकतो किंवा तो पूर्णपणे दुर्लक्ष करू शकतो आणि कार्यान्वित करणे सुरू ठेवू शकतो. थ्रेड टर्मिनेशन सिग्नलला प्रतिसादाचे वर्णन करणे ही प्रोग्रामरची जबाबदारी आहे.

Java मध्ये इंटरप्शन नावाची अंगभूत थ्रेड सूचना यंत्रणा आहे, जी आम्ही लवकरच पाहू, परंतु प्रथम खालील कोड पहा:

Incremenator हा एक थ्रेड आहे जो स्टॅटिक व्हेरिएबल Program.mValue च्या व्हॅल्यूमधून प्रत्येक सेकंदाला एक जोडतो किंवा वजा करतो. Incremenator मध्ये दोन खाजगी फील्ड असतात - mIsIncrement आणि mFinish. कोणती क्रिया केली जाते हे बुलियन व्हेरिएबल mIsIncrement द्वारे निर्धारित केले जाते - जर ते खरे असेल, तर एकाची बेरीज केली जाते, अन्यथा वजाबाकी केली जाते. आणि mFinish मूल्य सत्य झाल्यावर थ्रेड संपतो.

वर्ग वाढवणारा थ्रेड विस्तारित करतो (//अस्थिर कीवर्ड बद्दल - खाजगी अस्थिर बुलियन mIsIncrement = सत्याच्या खाली; खाजगी अस्थिर बुलियन mFinish = असत्य; सार्वजनिक शून्य परिवर्तनAction() // क्रिया विरुद्ध बदलते ( mIsIncrement = !mIsIncrement; ) v सार्वजनिक finish( ) // थ्रेड पूर्ण करणे सुरू करते ( mFinish = true; ) @Override public void run() ( do ( if(!mFinish) // ( if(mIsIncrement) Program.mValue++; // समाप्त करण्याची गरज तपासते //Increment else Program.mValue-; //Decrement // व्हेरिएबलचे वर्तमान मूल्य आउटपुट करा (Program.mValue + ""); अन्यथा थ्रेड रिटर्न करा ); //साइड थ्रेड ऑब्जेक्ट पब्लिक स्टॅटिक व्हॉइड मेन(स्ट्रिंग आर्ग्स) ( mInc = नवीन इन्क्रिमेनेटर(); //थ्रेड तयार करणे System.out.print("Value = "); mInc.start(); //थ्रेड सुरू करा //वृद्धीची क्रिया तीन वेळा बदला // (int i = 1; i) साठी i*2 सेकंदांच्या अंतराने<= 3; i++) { try{ Thread.sleep(i*2*1000); //Ожидание в течении i*2 сек. }catch(InterruptedException e){} mInc.changeAction(); //Переключение действия } mInc.finish(); //Инициация завершения побочного потока } } Консоль: Значение = 1 2 1 0 -1 -2 -1 0 1 2 3 4

तुम्ही ChangeAction() पद्धत (वजाबाकी जोडण्यासाठी आणि उलट बदलण्यासाठी) आणि फिनिश() पद्धत (प्रवाह संपुष्टात आणण्यासाठी) वापरून प्रवाहाशी संवाद साधू शकता.

अस्थिर कीवर्ड mIsIncrement आणि mFinish व्हेरिएबल्सच्या घोषणेमध्ये वापरले गेले. हे भिन्न थ्रेड्सद्वारे वापरल्या जाणाऱ्या चलांसाठी वापरणे आवश्यक आहे. याचे कारण असे की नॉन-व्होलॅटाइल व्हेरिएबलचे मूल्य प्रत्येक थ्रेडसाठी स्वतंत्रपणे कॅश केले जाऊ शकते आणि त्या कॅशेमधील मूल्य प्रत्येक थ्रेडसाठी भिन्न असू शकते. अस्थिर कीवर्डसह व्हेरिएबल घोषित केल्याने अशा प्रकारचे कॅशिंग अक्षम होते आणि व्हेरिएबलच्या सर्व विनंत्या थेट मेमरीमध्ये पाठवल्या जातील.

हे उदाहरण दाखवते की तुम्ही थ्रेडमधील संवाद कसे व्यवस्थित करू शकता. तथापि, थ्रेड पूर्ण करण्याच्या या दृष्टिकोनात एक समस्या आहे - इंक्रिमेनेटर mFinish फील्डचे मूल्य प्रति सेकंद एकदा तपासतो, त्यामुळे Finish() पद्धत अंमलात आणली जाते आणि प्रत्यक्षात थ्रेड दरम्यान काही सेकंदाचा कालावधी असू शकतो. समाप्त बाहेरून सिग्नल मिळाल्यावर, स्लीप() पद्धत परत केली आणि थ्रेड त्वरित संपुष्टात आला तर ते चांगले होईल. ही परिस्थिती हाताळण्यासाठी, व्यत्यय नावाचे एक अंगभूत थ्रेड सूचना साधन आहे.

व्यत्यय

थ्रेड क्लासमध्ये इंक्रिमेनेटर प्रोग्राममधील mFinish फील्ड प्रमाणेच छुपे बूलियन फील्ड आहे, ज्याला इंटरप्ट फ्लॅग म्हणतात. हा ध्वज थ्रेडच्या इंटरप्ट() पद्धतीला कॉल करून सेट केला जाऊ शकतो. हा ध्वज सेट आहे की नाही हे तपासण्याचे दोन मार्ग आहेत. पहिला मार्ग म्हणजे थ्रेड ऑब्जेक्टच्या bool isInterrupted() पद्धतीला कॉल करणे, दुसरा स्टॅटिक bool Thread.interrupted() पद्धतीला कॉल करणे. पहिली पद्धत व्यत्यय ध्वजाची स्थिती परत करते आणि ध्वज अस्पर्श ठेवते. दुसरी पद्धत ध्वजाची स्थिती परत करते आणि ती रीसेट करते. लक्षात घ्या की Thread.interrupted() ही थ्रेड क्लासची एक स्थिर पद्धत आहे आणि तिचा कॉल ज्या थ्रेडवरून कॉल केला होता त्याच्या इंटरप्ट फ्लॅगचे मूल्य परत करतो. म्हणून, ही पद्धत केवळ थ्रेडमधून कॉल केली जाते आणि थ्रेडला त्याची व्यत्यय स्थिती तपासण्याची परवानगी देते.

चला तर मग आपल्या कार्यक्रमाकडे परत जाऊया. व्यत्यय यंत्रणा आम्हाला थ्रेडच्या झोपेच्या समस्येचे निराकरण करण्यास अनुमती देईल. स्लीप(), प्रतीक्षा() आणि जॉइन() सारख्या थ्रेडच्या अंमलबजावणीला स्थगिती देणाऱ्या पद्धतींची एक खासियत आहे - जर थ्रेडची इंटरप्ट() पद्धत चालू असताना कॉल केली गेली, तर ते थ्रेडची वाट न पाहता एक InterruptedException टाकतील. कालबाह्य समाप्ती.

चला Incremenator प्रोग्राम पुन्हा काम करू - आता, Finish() पद्धत वापरून थ्रेड संपवण्याऐवजी, आपण मानक interrupt() पद्धत वापरू. आणि mFinish ध्वज तपासण्याऐवजी, आम्ही पद्धत bool Thread.interrupted();
व्यत्यय समर्थन जोडल्यानंतर वाढीव वर्ग हा कसा दिसेल:

वर्ग वाढवणारा थ्रेड वाढवतो ( खाजगी अस्थिर बुलियन mIsIncrement = सत्य; सार्वजनिक शून्य बदला () // क्रिया उलट करते ( mIsIncrement = !mIsIncrement; ) @Override public void run() ( do ( if(!Thread.interrupted()) / / व्यत्यय तपासा ( if(mIsIncrement) Program.mValue++; //Increment else Program.mValue--; //Decrement //आउटपुट व्हेरिएबलचे वर्तमान मूल्य System.out.print(Program.mValue + ""); ) अन्यथा परत करा // /थ्रेड संपवण्याचा प्रयत्न करा( Thread.sleep(1000); // 1 सेकंदासाठी धागा निलंबित करा. )catch(InterruptedException e)( परत करा; // व्यत्ययानंतर थ्रेड संपवा) ) तर(true) ) वर्ग कार्यक्रम ( //व्हेरिएबल); जो पब्लिक स्टॅटिक इंक्रिमेनेटर mInc; //साइड थ्रेड ऑब्जेक्ट पब्लिक स्टॅटिक व्हॉइड मेन (mInc = new Incremenator) वर चालतो; //थ्रेड सिस्टम तयार करणे out.print("व्हॅल्यू = "); //थ्रेड सुरू करा // i*2 सेकंदांच्या अंतराने (int i = 1; i<= 3; i++) { try{ Thread.sleep(i*2*1000); //Ожидание в течении i*2 сек. }catch(InterruptedException e){} mInc.changeAction(); //Переключение действия } mInc.interrupt(); //Прерывание побочного потока } } Консоль: Значение = 1 2 1 0 -1 -2 -1 0 1 2 3 4

तुम्ही बघू शकता, आम्ही फिनिश() पद्धतीपासून मुक्त झालो आणि बिल्ट-इन इंटरप्ट सिस्टम वापरून समान थ्रेड टर्मिनेशन यंत्रणा लागू केली. या अंमलबजावणीमध्ये, आम्हाला एक फायदा आहे - स्लीप() पद्धत थ्रेडमध्ये व्यत्यय आणल्यानंतर लगेच नियंत्रण (अपवाद टाका) परत करेल.

लक्षात घ्या की sleep() आणि join() पद्धती ट्राय-कॅच कन्स्ट्रक्टमध्ये गुंडाळल्या आहेत. या पद्धती कार्य करण्यासाठी ही एक आवश्यक अट आहे. त्यांना कॉल करणाऱ्या कोडने प्रतीक्षा करताना व्यत्यय आल्यावर टाकलेला InterruptedException पकडला पाहिजे.

आम्ही थ्रेड्सची सुरुवात आणि शेवटची क्रमवारी लावली आहे, त्यानंतर मी थ्रेड्ससह काम करताना वापरल्या जाणाऱ्या पद्धतींबद्दल बोलेन.

Thread.sleep() पद्धत

Thread.sleep() ही थ्रेड क्लासची एक स्थिर पद्धत आहे जी ज्या थ्रेडवर कॉल केली होती त्याची अंमलबजावणी स्थगित करते. स्लीप() पद्धत चालू असताना, सिस्टम थ्रेडला प्रोसेसर वेळ वाटप करणे थांबवते, ते इतर थ्रेड्समध्ये वितरित करते. स्लीप() पद्धत एकतर निर्दिष्ट वेळेसाठी (मिलीसेकंद किंवा नॅनोसेकंद) किंवा व्यत्ययाने थांबेपर्यंत कार्यान्वित करू शकते (अशा परिस्थितीत ती व्यत्यय आणेल).

Thread.sleep(1500); // दीड सेकंद प्रतीक्षा करते Thread.sleep(2000, 100); //2 सेकंद आणि 100 नॅनोसेकंद प्रतीक्षा करते

स्लीप() पद्धतीला प्रतीक्षा करण्यासाठी नॅनोसेकंद लागू शकतात, तरीही ते हलके घेतले जाऊ नये. बऱ्याच प्रणालींमध्ये, प्रतीक्षा वेळ अजूनही मिलीसेकंद किंवा दहापटांपर्यंत पूर्ण केला जातो.

yild() पद्धत

स्टॅटिक Thread.yield() पद्धतीमुळे प्रोसेसर सिस्टमवरील इतर थ्रेड्सवर प्रक्रिया करण्यासाठी स्विच करतो. पद्धत उपयुक्त ठरू शकते, उदाहरणार्थ, जेव्हा एखादा थ्रेड घटना घडण्याची वाट पाहत असतो आणि शक्य तितक्या वेळा त्याची घटना तपासणे आवश्यक असते. या प्रकरणात, तुम्ही इव्हेंट चेक आणि Thread.yield() पद्धत लूपमध्ये ठेवू शकता:

//संदेश येण्याची प्रतीक्षा करत असताना(!msgQueue.hasMessages()) // रांगेत कोणतेही संदेश नसताना ( Thread.yield(); // इतर थ्रेडवर नियंत्रण हस्तांतरित करा)

join() पद्धत

जावा एका थ्रेडला दुसऱ्या थ्रेडची अंमलबजावणी पूर्ण होईपर्यंत प्रतीक्षा करण्याची परवानगी देणारी यंत्रणा प्रदान करते. यासाठी join() पद्धत वापरली जाते. उदाहरणार्थ, मुख्य थ्रेडला साइड थ्रेड myThready पूर्ण होण्याची प्रतीक्षा करण्यासाठी, तुम्हाला मुख्य थ्रेडवर myThready.join() स्टेटमेंट जारी करणे आवश्यक आहे. एकदा myThready बाहेर पडल्यानंतर, join() पद्धत परत येते आणि मुख्य थ्रेड कार्यान्वित करणे सुरू ठेवू शकतो.

join() पद्धतीमध्ये ओव्हरलोड आहे जे पॅरामीटर म्हणून कालबाह्य होते. या प्रकरणात, join() थ्रेड पूर्ण होण्याची वाट पाहत असताना किंवा कालबाह्य झाल्यावर परत येतो. Thread.sleep() पद्धतीप्रमाणे, जॉइन पद्धत मिलिसेकंद आणि नॅनोसेकंदची प्रतीक्षा करू शकते - वितर्क समान आहेत.

थ्रेडची कालबाह्यता सेट करून, तुम्ही, उदाहरणार्थ, मुख्य (किंवा इतर कोणताही) थ्रेड संसाधन-केंद्रित ऑपरेशन्स पूर्ण करण्यासाठी साइड थ्रेडची प्रतीक्षा करत असताना ॲनिमेटेड प्रतिमा अद्यतनित करू शकता:

विचारवंत मेंदू = नवीन विचारक (); //विचारक हा थ्रेड वर्गाचा वंशज आहे. brain.start(); // "विचार" सुरू करा. do ( mThinkIndicator.refresh(); //mThinkIndicator - ॲनिमेटेड चित्र. प्रयत्न करा( brain.join(250); //विचार पूर्ण होण्यासाठी एक चतुर्थांश सेकंद प्रतीक्षा करा. ) पकडा(InterruptedException e)() ) असताना(मेंदू .जिवंत आहे()); //मेंदू विचार करत असताना... //मेंदूने विचार पूर्ण केला आहे (टाळ्या आहेत).

या उदाहरणात, मेंदूचा धागा एखाद्या गोष्टीबद्दल विचार करत आहे आणि असे करण्यास बराच वेळ लागेल अशी अपेक्षा आहे. मुख्य थ्रेड एक चतुर्थांश सेकंदासाठी त्याची वाट पाहतो आणि विचार करण्यासाठी ही वेळ पुरेशी नसल्यास, "विचार निर्देशक" (काही ॲनिमेटेड चित्र) अद्यतनित करतो. परिणामी, विचार करत असताना, वापरकर्ता स्क्रीनवर विचार प्रक्रियेचे एक सूचक पाहतो, ज्यामुळे त्याला कळते की इलेक्ट्रॉनिक मेंदू कशात तरी व्यस्त आहेत.

थ्रेड प्राधान्यक्रम

सिस्टममधील प्रत्येक थ्रेडचे स्वतःचे प्राधान्य असते. प्राधान्य म्हणजे थ्रेड ऑब्जेक्टमधील काही संख्या, ज्याचे उच्च मूल्य म्हणजे उच्च प्राधान्य. सिस्टम प्रथम उच्च प्राधान्य थ्रेड्स कार्यान्वित करते आणि कमी प्राधान्य थ्रेड्सना CPU वेळ फक्त तेव्हाच प्राप्त होतो जेव्हा त्यांचे अधिक विशेषाधिकार असलेले समकक्ष निष्क्रिय असतात.

तुम्ही दोन फंक्शन्स वापरून थ्रेड प्राधान्यांसह कार्य करू शकता:

व्हॉइड सेट प्रायोरिटी (इंट प्रायॉरिटी)- थ्रेडचे प्राधान्य सेट करते.
संभाव्य प्राधान्य मूल्ये MIN_PRIORITY, NORM_PRIORITY आणि MAX_PRIORITY आहेत.

int getPriority()- थ्रेडला प्राधान्य मिळते.

थ्रेड क्लासच्या काही उपयुक्त पद्धती

व्यावहारिकदृष्ट्या एवढेच. शेवटी, प्रवाहांसह कार्य करण्यासाठी येथे काही उपयुक्त पद्धती आहेत.

बुलियन isAlive()- myThready() चालू असल्यास खरे आणि थ्रेड अद्याप सुरू झाला नसल्यास किंवा संपुष्टात आल्यास असत्य परत करतो.

setName(स्ट्रिंग थ्रेडनेम)- प्रवाहाचे नाव निर्दिष्ट करते.
स्ट्रिंग getName()- थ्रेडचे नाव मिळते.
थ्रेडचे नाव त्याच्याशी संबंधित एक स्ट्रिंग आहे, जे काही प्रकरणांमध्ये कोणता थ्रेड क्रिया करत आहे हे समजण्यास मदत करते. कधीकधी हे उपयुक्त ठरू शकते.

स्थिर थ्रेड Thread.currentThread()- एक स्थिर पद्धत जी थ्रेडचा ऑब्जेक्ट परत करते ज्यामध्ये तो कॉल केला होता.

लांब getId()- थ्रेड आयडेंटिफायर परत करतो. अभिज्ञापक हा प्रवाहाला नियुक्त केलेला एक अद्वितीय क्रमांक आहे.

निष्कर्ष

मी लक्षात घेतो की लेख मल्टीथ्रेडेड प्रोग्रामिंगच्या सर्व सूक्ष्म गोष्टींबद्दल बोलत नाही. आणि उदाहरणांमध्ये दिलेल्या कोडमध्ये पूर्णपणे बरोबर असण्यासाठी काही बारकावे नाहीत. विशेषतः, उदाहरणे सिंक्रोनाइझेशन वापरत नाहीत. थ्रेड सिंक्रोनाइझेशन हा एक विषय आहे ज्याशिवाय तुम्ही योग्य मल्टी-थ्रेडेड ॲप्लिकेशन्स प्रोग्राम करू शकणार नाही. आपण याबद्दल वाचू शकता, उदाहरणार्थ, “जावा कॉन्करन्सी इन प्रॅक्टिस” या पुस्तकात किंवा जावा थ्रेड्सबद्दल शिकण्यापूर्वी, नजीकच्या भविष्यात पाहू या. कल्पना करा की तुम्ही तुमचा बायोडाटा सबमिट केला आणि मुलाखत घेतली. तुम्हाला आणि काही डझन भावी सहकाऱ्यांना एका मोठ्या सॉफ्टवेअर कंपनीत काम करण्यासाठी आमंत्रित केले आहे. इतर अडचणींपैकी, तुम्ही थकलेल्या एचआर कर्मचाऱ्याला नोकरीसाठी कागदी कागदपत्रे सादर करणे आवश्यक आहे.

प्रक्रियेला गती देण्यासाठी, पदासाठी अर्जदारांना दोन गटांमध्ये विभागले जाऊ शकते आणि दोन एचआर व्यवस्थापकांमध्ये (कंपनीमध्ये कोणी असल्यास) वितरित केले जाऊ शकते. परिणामी, आम्हाला समांतर ( समांतर) डिझाइन कार्य.

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

किंवा दुसर्या तत्त्वानुसार: खालच्या गटात जास्त लोक असल्याने, आम्ही एका मुलासाठी दोन मुली बदलू.

काम आयोजित करण्याचा हा मार्ग म्हणतात मल्टी-थ्रेडेड. आमचे थकलेले एचआर अधिकारी त्यांच्याकडून पुढील कर्मचारी भरती करण्यासाठी वेगवेगळ्या गटांमध्ये स्विच करतात. कदाचित अकरा गट आणि चार कर्मचारी अधिकारी आहेत. या प्रकरणात, मल्टी-थ्रेडेड ( मल्टीथ्रेडिंग) प्रक्रिया समांतरपणे अनेक एचआरद्वारे केली जाईल, जे कोणत्याही गटातील पुढील व्यक्तीला त्याच्या कागदपत्रांवर प्रक्रिया करण्यासाठी घेऊ शकतात.

प्रक्रिया

प्रक्रिया ( प्रक्रिया) या प्रकरणात कागदपत्रे प्राप्त करण्यासाठी कामाची संघटना असेल. संस्थेमध्ये, अनेक प्रक्रिया ओळखल्या जाऊ शकतात: लेखांकन, सॉफ्टवेअर डेव्हलपमेंट, क्लायंटसह मीटिंग्ज, वेअरहाऊस ऑपरेशन्स इ. प्रत्येक प्रक्रियेसाठी संसाधने वाटप केली जातात: परिसर, त्याच्या अंमलबजावणीसाठी कर्मचारी. प्रक्रिया एकमेकांपासून वेगळ्या आहेत: एचआर अधिकाऱ्यांना अकाउंटिंग डेटाबेसमध्ये प्रवेश नाही आणि ग्राहक सेवा व्यवस्थापक वेअरहाऊसच्या आसपास धावत नाहीत. एखाद्या प्रक्रियेला दुसऱ्याच्या संसाधनांमध्ये प्रवेश मिळवणे आवश्यक असल्यास, आंतर-प्रक्रिया संप्रेषण स्थापित करणे आवश्यक आहे: मेमो, संयुक्त बैठका.

प्रवाह

प्रक्रियेतील कार्य थ्रेड्स (जावा थ्रेड) च्या स्वरूपात आयोजित केले जाते. एचआर विभागासाठी, प्रवाह ही समूहाची सेवा करण्यासाठी कामाची संघटना आहे. पहिल्या चित्रात एक प्रवाह आहे, पुढच्या तीन चित्रात दोन आहेत. प्रक्रियेत, थ्रेड्स समांतरपणे कार्यान्वित केले जाऊ शकतात - दोन एचआर अधिकारी भविष्यातील कर्मचाऱ्यांचे दोन किंवा अधिक गट स्वीकारतात. गटांसह कर्मचारी अधिकाऱ्यांच्या परस्परसंवादाला - प्रक्रियेतील प्रवाहांची प्रक्रिया - म्हणतात थ्रेड सिंक्रोनाइझेशन. एका कर्मचारी अधिकाऱ्याने केलेल्या दोन गटांच्या रचनेचे रेखाचित्र पद्धती दर्शवतात: गणवेश (मुलगी - मुलगा - मुलगी - मुलगा) आणि भिन्न प्राधान्यांसह (एका मुलासह दोन मुली पर्यायी). थ्रेड्सना ते ज्या प्रक्रियेशी संबंधित आहेत त्या संसाधनांमध्ये प्रवेश आहे: एचआर अधिकाऱ्याच्या गटांना अर्जाचे नमुने, कागदपत्रे भरण्यासाठी पेन दिले जातात. परंतु जर प्रवाह त्यांच्या सामान्य गोष्टींशी संवाद साधत असतील तर घटना शक्य आहेत. जर कर्मचारी अधिकाऱ्याने तुम्हाला रांगेतील शेवटच्या व्यक्तीचे नाव ओरडण्यास सांगितले तर, दोन गटांच्या बाबतीत, तो एखाद्या स्त्रीचे किंवा पुरुषाचे नाव ऐकेल की नाही याची त्याला आगाऊ खात्री नसते. अशा डेटा ऍक्सेस विवाद, अवरोधित करणे आणि त्यांचे निराकरण करण्याचे मार्ग हा एक अतिशय महत्त्वाचा विषय आहे.

प्रवाह अवस्था

प्रत्येक थ्रेड खालीलपैकी एका स्थितीत आहे:
  • तयार (नवीन) – एचआर अधिकाऱ्याची ओळ तयार होत आहे, लोक संघटित होत आहेत.
  • धावण्यायोग्य - आमची रांग HR अधिकाऱ्यासाठी उभी आहे आणि त्यावर प्रक्रिया केली जात आहे.
  • अवरोधित - रांगेतील शेवटचा माणूस नावाने ओरडण्याचा प्रयत्न करतो, परंतु जेव्हा त्याने ऐकले की पुढच्या गटातील एक मुलगी त्याच्यासमोर असे करू लागली तेव्हा तो गप्प झाला.
  • समाप्त - संपूर्ण रांग एचआर अधिकाऱ्याने पूर्ण केली आहे आणि त्याची गरज नाही.
  • वाट पाहत आहे - एक रांग दुसरीकडून सिग्नलची वाट पाहत आहे.
थ्रेड्सची संघटना आणि त्यांचे परस्परसंवाद प्रक्रियांच्या प्रभावी ऑपरेशनसाठी आधार आहे.

चला आयटी जगाकडे परत जाऊया

21 व्या शतकात, बहु-थ्रेडेड आणि समांतर अंमलबजावणी प्रासंगिक बनली आहे. गेल्या शतकाच्या 90 च्या दशकापासून, विंडोज, मॅकओएस आणि लिनक्स या मल्टीटास्किंग ऑपरेटिंग सिस्टम होम कॉम्प्युटरवर दृढपणे स्थापित झाल्या आहेत. तुम्हाला त्यांच्यामध्ये चार किंवा अधिक कोर प्रोसेसर सापडतील. GPU व्हिडिओ कार्डच्या समांतर ब्लॉक्सची संख्या आधीच एक हजार ओलांडली आहे. लोकप्रिय प्रोग्राम मल्टीथ्रेडिंग (मल्टीथ्रेडिंग) विचारात घेऊन लिहिलेले आहेत, उदाहरणार्थ, ग्राफिक्स, व्हिडिओ किंवा मोठ्या प्रमाणात डेटा ऑपरेट करण्यासाठी सॉफ्टवेअरच्या आधुनिक आवृत्त्या: Adobe Photoshop, WinRar, Mathematica, आधुनिक गेम. जावा मल्टीथ्रेडिंग हा अतिशय महत्त्वाचा, लोकप्रिय आणि गुंतागुंतीचा विषय आहे. म्हणून, JavaRush कोर्समध्ये ते चांगल्या प्रकारे समजून घेण्यासाठी अनेक कार्ये आहेत. मल्टीथ्रेडिंगवरील जावा उदाहरणे तुम्हाला या क्षेत्रातील मूलभूत बारकावे आणि बारकावे जाणून घेण्यास मदत करतील, थ्रेड्सचे कार्य समक्रमित करा.

प्रक्रिया

प्रक्रिया(प्रक्रिया) – ऑपरेटिंग सिस्टम (OS) ने मेमरी, प्रोसेसर वेळ/कोर आणि इतर संसाधने वाटप केलेल्या प्रोग्रामचे चालू उदाहरण. हे महत्वाचे आहे की मेमरी स्वतंत्रपणे वाटप केली जाते; प्रक्रियांना संवाद साधण्याची आवश्यकता असल्यास, ते फाइल्स, पाईप्स आणि इतर आंतरप्रक्रिया संप्रेषण पद्धती वापरून तसे करू शकतात.

प्रवाह

जावा थ्रेड (धागा). काहीवेळा, इतर Java वर्गांमध्ये गोंधळ न होण्यासाठी - स्ट्रीम आणि यासारख्या, जावा स्ट्रीम्सचे अनेकदा थ्रेड म्हणून भाषांतर केले जाते. ते एखाद्या प्रक्रियेसाठी वाटप केलेली संसाधने वापरतात आणि प्रक्रिया ज्या प्रकारे अंमलात आणली जाते. मुख्य थ्रेड मुख्य पद्धत कार्यान्वित करतो आणि बाहेर पडतो. जेव्हा एखादी प्रक्रिया पार पाडली जाते, तेव्हा अतिरिक्त थ्रेड्स (चाइल्ड थ्रेड्स) तयार केले जाऊ शकतात. समान प्रक्रियेचे थ्रेड एकमेकांशी डेटाची देवाणघेवाण करू शकतात. जावा मल्टीथ्रेडिंगसाठी डेटा सिंक्रोनाइझेशन विचारात घेणे आवश्यक आहे, याबद्दल विसरू नका. Java मध्ये, शेवटचा थ्रेड पूर्ण झाल्यावर प्रक्रिया संपुष्टात येते. पार्श्वभूमी कार्यांसाठी, एक थ्रेड डिमन म्हणून लाँच केला जाऊ शकतो, जो नेहमीच्या पेक्षा वेगळा असतो कारण प्रक्रियेचे सर्व गैर-डिमॉन थ्रेड्स संपुष्टात आल्यावर ते जबरदस्तीने बंद केले जातील.

प्रथम बहु-थ्रेडेड अनुप्रयोग

JavaRush कोर्समध्ये थ्रेड तयार करण्याचे अर्धा डझनहून अधिक मार्ग आहेत; आम्ही त्यांचे तपशीलवार परीक्षण करू. प्रथम, मूलभूत गोष्टींपैकी एकाशी परिचित होऊ या. रन() पद्धतीमध्ये एक विशेष क्लास थ्रेड आहे जिथे तुम्हाला प्रोग्राम लॉजिक लागू करणारा कोड लिहावा लागेल. थ्रेड तयार केल्यानंतर, तुम्ही start() पद्धतीवर कॉल करून ते सुरू करू शकता. जावा मल्टीथ्रेडिंगचे उदाहरण लागू करणारा डेमो प्रोग्राम लिहू. वर्ग लोकरांग थ्रेड विस्तारित करते ( // आमची कर्मचाऱ्यांची रांग, थ्रेड वर्गाचे वंशजखाजगी स्ट्रिंग नावे; लोकांची रांग(स्ट्रिंग...नावे) ( // कन्स्ट्रक्टर, युक्तिवाद - कर्मचाऱ्यांच्या नावांची ॲरेहे नावे = नावे; ) @ओव्हरराइड सार्वजनिक शून्य रन () ( // थ्रेड सुरू झाल्यावर ही पद्धत कॉल केली जाईलसाठी (int i = 0; i< names. length; i++ ) { // पुढील कर्मचाऱ्याला 0.5 सेकंदांच्या विरामाने लूपमध्ये आउटपुट कराप्रणाली. बाहेर println( "कागदपत्रांवर प्रक्रिया केली:"+ नावे[i] ); प्रयत्न करा ( झोपा ( 500 ); // विलंब 0.5 से) पकडणे (अपवाद ई) ( ) ) ) ) सार्वजनिक वर्ग एचआर ( // धागा कसा कार्य करतो हे दाखवण्यासाठी वर्गसार्वजनिक स्थिर शून्य मुख्य (स्ट्रिंग आर्ग्स) ( // दोन रांगा तयार करा PeopleQueue queue1 = नवीन PeopleQueue ("Ivan", "Sergey", "Nikolai", "Ferdinand", "Vasily"); PeopleQueue queue2 = नवीन PeopleQueue ("मारिया", "ल्युडमिला", "एलिस", "करीना", "ओल्गा"); प्रणाली. बाहेर println("प्रारंभ!"); // कार्यक्रमाच्या मुख्य धाग्यावरील संदेशरांग1. start(); //एक रांग सुरू करा (बाल धागा)रांग2. start(); //दुसरा सुरू करा (बाल धागा)) ) चला कार्यक्रम सुरू करूया. कन्सोल मुख्य थ्रेडमधून संदेश आउटपुट प्रदर्शित करते. पुढे, प्रत्येक चाइल्ड थ्रेड queue1 आणि queue2 पुढील प्रक्रिया केलेल्या कर्मचाऱ्याबद्दल त्यांच्या सामान्य कन्सोलवर संदेश आउटपुट करते. प्रोग्रामसाठी संभाव्य पर्यायांपैकी एक: चला प्रारंभ करूया! प्रक्रिया केलेले दस्तऐवज: मारिया प्रक्रिया केलेले दस्तऐवज: इव्हान प्रक्रिया केलेले दस्तऐवज: ल्युडमिला प्रक्रिया केलेले दस्तऐवज: सर्जी प्रक्रिया केलेले दस्तऐवज: अलिसा प्रक्रिया केलेले दस्तऐवज: निकोले प्रक्रिया केलेले दस्तऐवज: करीना प्रक्रिया केलेले दस्तऐवज: फर्डिनांड प्रक्रिया केलेले दस्तऐवज: ओल्गा प्रक्रिया केलेले दस्तऐवज: व्हॅसिली प्रक्रिया निर्गमन कोड 0 सह समाप्त Java मध्ये मल्टीथ्रेडिंग- विषय अवघड आणि बहुआयामी आहे. समांतर, मल्टीटास्किंग आणि मल्टीथ्रेडेड कंप्युटिंग वापरून कोड लिहिण्याची क्षमता तुम्हाला आधुनिक मल्टी-कोर प्रोसेसर आणि अनेक कॉम्प्युटर असलेल्या क्लस्टरवर कार्ये प्रभावीपणे अंमलात आणण्यास मदत करेल.

आम्ही वाचण्याची शिफारस करतो

वर