CodeGym /Java Blog /अनियमित /बेहतर एक साथ: जावा और थ्रेड क्लास। भाग I - निष्पादन के सू...
John Squirrels
स्तर 41
San Francisco

बेहतर एक साथ: जावा और थ्रेड क्लास। भाग I - निष्पादन के सूत्र

अनियमित ग्रुप में प्रकाशित

परिचय

जावा में शुरुआत से ही मल्टीथ्रेडिंग का निर्माण किया गया था। तो, आइए संक्षेप में मल्टीथ्रेडिंग नामक इस चीज़ को देखें। बेहतर एक साथ: जावा और थ्रेड क्लास।  भाग I - निष्पादन के सूत्र - 1हम Oracle के आधिकारिक पाठ को एक संदर्भ बिंदु के रूप में लेते हैं: " पाठ: "हैलो वर्ल्ड!" एप्लिकेशन "। हम अपने हैलो वर्ल्ड प्रोग्राम के कोड को इस प्रकार थोड़ा बदल देंगे:

class HelloWorldApp {
    public static void main(String[] args) {
        System.out.println("Hello, " + args[0]);
    }
}
argsप्रोग्राम प्रारंभ होने पर पास किए गए इनपुट पैरामीटर की एक सरणी है। इस कोड को एक फ़ाइल में ऐसे नाम से सहेजें जो वर्ग के नाम से मेल खाता हो और जिसका एक्सटेंशन .java. जावैक उपयोगिता का उपयोग करके इसे संकलित करें : javac HelloWorldApp.java. फिर, हम अपने कोड को कुछ पैरामीटर के साथ चलाते हैं, उदाहरण के लिए, "रोजर": java HelloWorldApp Roger बेहतर एक साथ: जावा और थ्रेड क्लास।  भाग I - निष्पादन के सूत्र - 2हमारे कोड में वर्तमान में एक गंभीर दोष है। यदि आप कोई तर्क पारित नहीं करते हैं (यानी केवल "जावा हैलोवर्ल्ड ऐप" निष्पादित करें), तो हमें एक त्रुटि मिलती है:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
        at HelloWorldApp.main(HelloWorldApp.java:3)
"मुख्य" नामक थ्रेड में एक अपवाद (यानी एक त्रुटि) उत्पन्न हुई। तो, जावा में धागे हैं? यहीं से हमारी यात्रा शुरू होती है।

जावा और थ्रेड्स

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

class HelloWorldApp {
    public static void main(String[] args) {
		while (true) { 
			// Do nothing
		}
	}
}
अब इसे फिर से कंपाइल करते हैं javac। सुविधा के लिए, हम अपने जावा कोड को एक अलग विंडो में चलाएंगे। विंडोज़ पर, इसे इस तरह किया जा सकता है: start java HelloWorldApp. अब हम jps उपयोगिता का उपयोग यह देखने के लिए करेंगे कि जावा हमें कौन सी जानकारी बता सकता है: बेहतर एक साथ: जावा और थ्रेड क्लास।  भाग I - निष्पादन के सूत्र - 3पहला नंबर PID या प्रोसेस आईडी है। एक प्रक्रिया क्या है?

A process is a combination of code and data sharing a common virtual address space.
प्रक्रियाओं के साथ, अलग-अलग प्रोग्राम एक दूसरे से अलग होते हैं जैसे वे चलते हैं: प्रत्येक एप्लिकेशन अन्य प्रोग्रामों में हस्तक्षेप किए बिना स्मृति में अपने क्षेत्र का उपयोग करता है। अधिक जानने के लिए, मैं इस ट्यूटोरियल को पढ़ने की सलाह देता हूं: प्रोसेस और थ्रेड्स । एक थ्रेड के बिना एक प्रक्रिया मौजूद नहीं हो सकती है, इसलिए यदि कोई प्रक्रिया मौजूद है, तो उसमें कम से कम एक थ्रेड है। लेकिन यह जावा में कैसे आता है? जब हम जावा प्रोग्राम शुरू करते हैं, तो निष्पादन mainविधि से शुरू होता है। यह ऐसा है जैसे हम प्रोग्राम में कदम रख रहे हैं, इसलिए इस विशेष mainतरीके को एंट्री पॉइंट कहा जाता है। विधि mainहमेशा "सार्वजनिक स्थैतिक शून्य" होनी चाहिए, ताकि जावा वर्चुअल मशीन (जेवीएम) हमारे प्रोग्राम को निष्पादित करना शुरू कर सके। अधिक जानकारी के लिए, जावा मुख्य विधि स्थिर क्यों है?. यह पता चला है कि जावा लॉन्चर (java.exe या javaw.exe) एक साधारण सी एप्लिकेशन है: यह विभिन्न DLL को लोड करता है जिसमें वास्तव में JVM शामिल होता है। जावा लॉन्चर जावा नेटिव इंटरफेस (जेएनआई) कॉल का एक विशिष्ट सेट बनाता है। जेएनआई जावा वर्चुअल मशीन की दुनिया को सी ++ की दुनिया से जोड़ने के लिए एक तंत्र है। तो, लांचर स्वयं जेवीएम नहीं है, बल्कि इसे लोड करने का एक तंत्र है। यह JVM को शुरू करने के लिए निष्पादित करने के लिए सही आदेश जानता है। यह आवश्यक वातावरण स्थापित करने के लिए जेएनआई कॉल का उपयोग करना जानता है। इस वातावरण की स्थापना में मुख्य धागा बनाना शामिल है, जिसे निश्चित रूप से "मुख्य" कहा जाता है। बेहतर ढंग से वर्णन करने के लिए कि जावा प्रक्रिया में कौन से धागे मौजूद हैं, हम jvisualvm का उपयोग करते हैंउपकरण, जो JDK के साथ शामिल है। किसी प्रक्रिया की पीआईडी ​​​​को जानने के बाद, हम तुरंत उस प्रक्रिया के बारे में जानकारी देख सकते हैं: jvisualvm --openpid <process id> बेहतर एक साथ: जावा और थ्रेड क्लास।  भाग I - निष्पादन के सूत्र - 4दिलचस्प बात यह है कि प्रक्रिया को आवंटित मेमोरी में प्रत्येक थ्रेड का अपना अलग क्षेत्र होता है। इस मेमोरी स्ट्रक्चर को स्टैक कहा जाता है। ढेर में फ्रेम होते हैं। एक फ्रेम एक विधि के सक्रियण का प्रतिनिधित्व करता है (एक अधूरा विधि कॉल)। एक फ्रेम को StackTraceElement के रूप में भी दर्शाया जा सकता है ( StackTraceElement के लिए Java API देखें )। आप यहाँ चर्चा में प्रत्येक थ्रेड को आवंटित मेमोरी के बारे में अधिक जानकारी प्राप्त कर सकते हैं: " कैसे Java (JVM) प्रत्येक थ्रेड के लिए स्टैक आवंटित करता है "। यदि आप जावा एपीआई को देखते हैं और "थ्रेड" शब्द की खोज करते हैं, तो आपको java.lang.Thread मिल जाएगाकक्षा। यह वह वर्ग है जो जावा में एक थ्रेड का प्रतिनिधित्व करता है, और हमें इसके साथ काम करने की आवश्यकता होगी। बेहतर एक साथ: जावा और थ्रेड क्लास।  भाग I - निष्पादन के सूत्र - 5

java.lang.Thread

java.lang.Threadजावा में, एक थ्रेड को क्लास के उदाहरण द्वारा दर्शाया जाता है । आपको तुरंत समझना चाहिए कि थ्रेड क्लास के उदाहरण स्वयं निष्पादन के धागे नहीं हैं। यह JVM और ऑपरेटिंग सिस्टम द्वारा प्रबंधित निम्न-स्तरीय थ्रेड्स के लिए केवल एक प्रकार का API है। जब हम जावा लॉन्चर का उपयोग करके JVM शुरू करते हैं, तो यह main"मेन" नामक एक थ्रेड और कुछ अन्य हाउसकीपिंग थ्रेड्स बनाता है। जैसा कि JavaDoc में थ्रेड क्लास के लिए कहा गया है: When a Java Virtual Machine starts up, there is usually a single non-daemon thread. धागे 2 प्रकार के होते हैं: डेमॉन और गैर-डेमन। डेमन थ्रेड बैकग्राउंड (हाउसकीपिंग) थ्रेड हैं जो बैकग्राउंड में कुछ काम करते हैं। "डेमन" शब्द मैक्सवेल के राक्षस को संदर्भित करता है। आप इस विकिपीडिया लेख में अधिक जान सकते हैं । जैसा कि प्रलेखन में कहा गया है, JVM प्रोग्राम (प्रक्रिया) को तब तक निष्पादित करना जारी रखता है जब तक:
  • रनटाइम.एक्सिट () विधि को कहा जाता है
  • सभी गैर-डिमन थ्रेड्स अपना काम पूरा करते हैं (त्रुटियों के बिना या फेंके गए अपवादों के साथ)
इससे एक महत्वपूर्ण विवरण आता है: डेमन थ्रेड्स को किसी भी बिंदु पर समाप्त किया जा सकता है। नतीजतन, उनके डेटा की अखंडता के बारे में कोई गारंटी नहीं है। तदनुसार, डेमन थ्रेड्स कुछ हाउसकीपिंग कार्यों के लिए उपयुक्त हैं। उदाहरण के लिए, जावा में एक थ्रेड है जो प्रसंस्करण finalize()विधि कॉल के लिए ज़िम्मेदार है, यानी कचरा कलेक्टर (जीसी) से जुड़े धागे। प्रत्येक थ्रेड एक समूह ( ThreadGroup ) का हिस्सा है। और समूह अन्य समूहों का हिस्सा हो सकते हैं, जो एक निश्चित पदानुक्रम या संरचना बनाते हैं।

public static void main(String[] args) {
	Thread currentThread = Thread.currentThread();
	ThreadGroup threadGroup = currentThread.getThreadGroup();
	System.out.println("Thread: " + currentThread.getName());
	System.out.println("Thread Group: " + threadGroup.getName());
	System.out.println("Parent Group: " + threadGroup.getParent().getName());
}
समूह थ्रेड प्रबंधन के लिए आदेश लाते हैं। समूहों के अलावा, थ्रेड्स का अपना अपवाद हैंडलर होता है। एक उदाहरण देखें:

public static void main(String[] args) {
	Thread th = Thread.currentThread();
	th.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
		@Override
		public void uncaughtException(Thread t, Throwable e) {
			System.out.println("An error occurred: " + e.getMessage());
		}
	});
    System.out.println(2/0);
}
शून्य से भाग देने से एक त्रुटि होगी जो हैंडलर द्वारा पकड़ी जाएगी। यदि आप अपना स्वयं का हैंडलर निर्दिष्ट नहीं करते हैं, तो JVM डिफ़ॉल्ट हैंडलर को इनवॉइस करेगा, जो अपवाद के स्टैक ट्रेस को StdError में आउटपुट करेगा। प्रत्येक थ्रेड की प्राथमिकता भी होती है। आप इस लेख में प्राथमिकताओं के बारे में अधिक पढ़ सकते हैं: मल्टीथ्रेडिंग में जावा थ्रेड प्राथमिकता

धागा बनाना

जैसा कि प्रलेखन में बताया गया है, हमारे पास धागा बनाने के 2 तरीके हैं। पहला तरीका है अपना खुद का सबक्लास बनाना। उदाहरण के लिए:

public class HelloWorld{
    public static class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println("Hello, World!");  
        }
    }
    
    public static void main(String[] args) {
        Thread thread = new MyThread();
        thread.start();
    }
}
जैसा कि आप देख सकते हैं कि टास्क का काम मेथड में होता है , लेकिन मेथड run()में ही थ्रेड शुरू हो जाता है। start()इन विधियों को भ्रमित न करें: यदि हम सीधे r un()विधि को कहते हैं, तो कोई नया सूत्र प्रारंभ नहीं होगा। यह वह start()तरीका है जो JVM को नया थ्रेड बनाने के लिए कहता है। यह विकल्प जहां हम थ्रेड को इनहेरिट करते हैं वह पहले से ही खराब है जिसमें हम थ्रेड को अपने वर्ग पदानुक्रम में शामिल करते हैं। दूसरी कमी यह है कि हम "एकल उत्तरदायित्व" सिद्धांत का उल्लंघन करने लगे हैं। अर्थात्, हमारी कक्षा एक साथ थ्रेड को नियंत्रित करने और इस थ्रेड में किए जाने वाले कुछ कार्यों के लिए ज़िम्मेदार है। सही तरीका क्या है? उत्तर उसी run()विधि में मिलता है, जिसे हम ओवरराइड करते हैं:

public void run() {
	if (target != null) {
		target.run();
	}
}
यहाँ, targetकुछ हैं java.lang.Runnable, जिन्हें हम थ्रेड क्लास का उदाहरण बनाते समय पास कर सकते हैं। इसका मतलब है कि हम यह कर सकते हैं:

public class HelloWorld{
    public static void main(String[] args) {
        Runnable task = new Runnable() {
            public void run() {
                System.out.println("Hello, World!");
            } 
        };
        Thread thread = new Thread(task);
        thread.start();
    }
}
Runnableजावा 1.8 के बाद से एक कार्यात्मक इंटरफ़ेस भी रहा है। इससे थ्रेड के कार्य के लिए और भी सुंदर कोड लिखना संभव हो जाता है:

public static void main(String[] args) {
	Runnable task = () -> { 
		System.out.println("Hello, World!");
	};
	Thread thread = new Thread(task);
	thread.start();
}

निष्कर्ष

मुझे उम्मीद है कि यह चर्चा स्पष्ट करती है कि एक धागा क्या है, धागे कैसे अस्तित्व में आते हैं, और धागे के साथ कौन से बुनियादी संचालन किए जा सकते हैं। अगले भाग में , हम यह समझने की कोशिश करेंगे कि धागे एक दूसरे के साथ कैसे इंटरैक्ट करते हैं और धागे के जीवन चक्र का पता लगाएंगे। बेहतर एक साथ: जावा और थ्रेड क्लास। भाग II - तुल्यकालन बेहतर एक साथ: जावा और थ्रेड वर्ग। भाग III - इंटरेक्शन बेटर टुगेदर: जावा और थ्रेड क्लास। भाग IV - कॉल करने योग्य, भविष्य और मित्र बेहतर एक साथ: जावा और थ्रेड वर्ग। भाग V - एक्ज़ीक्यूटर, थ्रेडपूल, फोर्क / जॉइन बेटर टुगेदर: जावा और थ्रेड क्लास। भाग VI - आग बुझाओ!
टिप्पणियां
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION