CodeGym /Java Blog /यादृच्छिक /एकत्र चांगले: Java आणि थ्रेड वर्ग. भाग I - अंमलबजावणीचे ध...
John Squirrels
पातळी 41
San Francisco

एकत्र चांगले: Java आणि थ्रेड वर्ग. भाग I - अंमलबजावणीचे धागे

यादृच्छिक या ग्रुपमध्ये प्रकाशित केले

परिचय

मल्टीथ्रेडिंग जावामध्ये अगदी सुरुवातीपासून तयार केले गेले. तर, मल्टीथ्रेडिंग नावाची ही गोष्ट थोडक्यात पाहू. एकत्र चांगले: Java आणि थ्रेड वर्ग.  भाग १ - अंमलबजावणीचे धागे - १आम्ही ओरॅकलकडून एक संदर्भ बिंदू म्हणून अधिकृत धडा घेतो: " धडा: "हॅलो वर्ल्ड!" अनुप्रयोग ". आम्ही आमच्या हॅलो वर्ल्ड प्रोग्रामच्या कोडमध्ये खालीलप्रमाणे किंचित बदल करू:

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

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
        at HelloWorldApp.main(HelloWorldApp.java:3)
"मुख्य" नावाच्या धाग्यात अपवाद (म्हणजे एक त्रुटी) आली. तर, जावामध्ये धागे आहेत? इथूनच आमचा प्रवास सुरू होतो.

जावा आणि धागे

थ्रेड म्हणजे काय हे समजून घेण्यासाठी, तुम्हाला Java प्रोग्राम कसा सुरू होतो हे समजून घेणे आवश्यक आहे. आपला कोड खालीलप्रमाणे बदलूया:

class HelloWorldApp {
    public static void main(String[] args) {
		while (true) { 
			// Do nothing
		}
	}
}
आता ते पुन्हा संकलित करू javac. सोयीसाठी, आम्ही आमचा Java कोड वेगळ्या विंडोमध्ये रन करू. विंडोजवर, हे असे केले जाऊ शकते: start java HelloWorldApp. आता Java आम्हाला कोणती माहिती सांगू शकते हे पाहण्यासाठी आम्ही jps युटिलिटी वापरू : एकत्र चांगले: Java आणि थ्रेड वर्ग.  भाग I - अंमलबजावणीचे धागे - 3पहिला क्रमांक PID किंवा प्रक्रिया आयडी आहे. प्रक्रिया म्हणजे काय?

A process is a combination of code and data sharing a common virtual address space.
प्रक्रियांसह, भिन्न प्रोग्राम्स चालत असताना एकमेकांपासून वेगळे केले जातात: प्रत्येक अनुप्रयोग इतर प्रोग्राममध्ये हस्तक्षेप न करता मेमरीमध्ये स्वतःचे क्षेत्र वापरतो. अधिक जाणून घेण्यासाठी, मी हे ट्यूटोरियल वाचण्याची शिफारस करतो: प्रक्रिया आणि थ्रेड्स . थ्रेडशिवाय प्रक्रिया अस्तित्वात असू शकत नाही, म्हणून जर प्रक्रिया अस्तित्त्वात असेल तर त्यात किमान एक धागा आहे. पण हे जावा मध्ये कसे येते? जेव्हा आपण जावा प्रोग्राम सुरू करतो, तेव्हा पद्धतीने अंमलबजावणी सुरू होते main. जणू काही आपण प्रोग्राममध्ये प्रवेश करत आहोत, म्हणून या विशेष mainपद्धतीला एंट्री पॉइंट म्हणतात. पद्धत mainनेहमी "पब्लिक स्टॅटिक व्हॉइड" असली पाहिजे, जेणेकरून Java व्हर्च्युअल मशीन (JVM) आमच्या प्रोग्रामची अंमलबजावणी सुरू करू शकेल. अधिक माहितीसाठी, Java मुख्य पद्धत स्थिर का आहे?. असे दिसून आले की Java लाँचर (java.exe किंवा javaw.exe) हे एक साधे सी ऍप्लिकेशन आहे: ते विविध DLL लोड करते ज्यामध्ये प्रत्यक्षात JVM समाविष्ट आहे. Java लाँचर Java नेटिव्ह इंटरफेस (JNI) कॉल्सचा विशिष्ट संच करतो. JNI ही Java आभासी मशीनचे जग C++ च्या जगाशी जोडणारी यंत्रणा आहे. तर, लाँचर स्वतः JVM नसून ते लोड करण्यासाठी एक यंत्रणा आहे. JVM सुरू करण्‍यासाठी कार्यान्‍वयित करण्‍याच्‍या बरोबर कमांडस् माहीत आहेत. आवश्यक वातावरण सेट करण्यासाठी जेएनआय कॉल कसे वापरायचे हे माहित आहे. हे वातावरण सेट करण्यामध्ये मुख्य धागा तयार करणे समाविष्ट आहे, ज्याला "मुख्य" म्हटले जाते. Java प्रक्रियेमध्ये कोणते थ्रेड अस्तित्त्वात आहेत हे चांगल्या प्रकारे स्पष्ट करण्यासाठी, आम्ही jvisualvm वापरतोसाधन, जे JDK सह समाविष्ट आहे. एखाद्या प्रक्रियेचा pid जाणून घेतल्यावर, आम्ही त्या प्रक्रियेबद्दल माहिती त्वरित पाहू शकतो: jvisualvm --openpid <process id> एकत्र चांगले: Java आणि थ्रेड वर्ग.  भाग I - अंमलबजावणीचे धागे - 4विशेष म्हणजे, प्रत्येक थ्रेडचे स्वतःचे स्वतंत्र क्षेत्र आहे प्रक्रियेसाठी वाटप केलेल्या मेमरीमध्ये. या मेमरी स्ट्रक्चरला स्टॅक म्हणतात. स्टॅकमध्ये फ्रेम्स असतात. एक फ्रेम पद्धतीचे सक्रियकरण दर्शवते (एक अपूर्ण पद्धत कॉल). एक फ्रेम StackTraceElement म्हणून देखील दर्शविली जाऊ शकते ( StackTraceElement साठी Java API पहा ). प्रत्येक थ्रेडला वाटप केलेल्या मेमरीबद्दल तुम्ही येथे चर्चेत अधिक माहिती मिळवू शकता: " Java (JVM) प्रत्येक थ्रेडसाठी स्टॅकचे वाटप कसे करते ". तुम्ही Java API पाहिल्यास आणि "थ्रेड" शब्द शोधल्यास, तुम्हाला java.lang.Thread सापडेल.वर्ग हा वर्ग आहे जो Java मधील थ्रेडचे प्रतिनिधित्व करतो आणि आम्हाला त्याच्यासोबत काम करावे लागेल. एकत्र चांगले: Java आणि थ्रेड वर्ग.  भाग I - अंमलबजावणीचे धागे - 5

java.lang.thread

Java मध्ये, वर्गाच्या उदाहरणाद्वारे थ्रेड दर्शविला जातो java.lang.Thread. तुम्ही ताबडतोब समजून घेतले पाहिजे की थ्रेड क्लासची उदाहरणे स्वतःच अंमलबजावणीचे थ्रेड नाहीत. JVM आणि ऑपरेटिंग सिस्टमद्वारे व्यवस्थापित केलेल्या निम्न-स्तरीय थ्रेडसाठी हे फक्त एक प्रकारचे API आहे. जेव्हा आपण Java लाँचर वापरून JVM सुरू करतो, तेव्हा तो main"मुख्य" नावाचा एक धागा आणि इतर काही गृहनिर्माण धागे तयार करतो. थ्रेड वर्गासाठी JavaDoc मध्ये सांगितल्याप्रमाणे: When a Java Virtual Machine starts up, there is usually a single non-daemon thread. थ्रेडचे 2 प्रकार आहेत: डिमन आणि नॉन-डेमन. डिमन थ्रेड्स हे बॅकग्राउंड (हाऊसकीपिंग) धागे आहेत जे बॅकग्राउंडमध्ये काही काम करतात. "डेमन" हा शब्द मॅक्सवेलच्या राक्षसाला सूचित करतो. आपण या विकिपीडिया लेखात अधिक जाणून घेऊ शकता . दस्तऐवजीकरणात म्हटल्याप्रमाणे, JVM प्रोग्राम (प्रक्रिया) कार्यान्वित करत राहते तोपर्यंत:
  • Runtime.exit () पद्धतीला म्हणतात
  • सर्व नॉन-डिमन थ्रेड्स त्यांचे कार्य पूर्ण करतात (त्रुटीशिवाय किंवा फेकलेल्या अपवादांशिवाय)
यावरून एक महत्त्वाचा तपशील पुढे येतो: डिमन थ्रेड्स कोणत्याही वेळी बंद केले जाऊ शकतात. परिणामी, त्यांच्या डेटाच्या अखंडतेबद्दल कोणतीही हमी नाही. त्यानुसार, डिमन धागे विशिष्ट घरकाम कार्यांसाठी योग्य आहेत. उदाहरणार्थ, Java मध्ये एक थ्रेड आहे जो मेथड कॉल्सच्या प्रक्रियेसाठी जबाबदार आहे finalize(), म्हणजे गार्बेज कलेक्टर (gc) शी गुंतलेले थ्रेड. प्रत्येक थ्रेड समूहाचा भाग आहे ( 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 वर आउटपुट करेल. प्रत्येक धाग्यालाही प्राधान्य असते. आपण या लेखातील प्राधान्यांबद्दल अधिक वाचू शकता: मल्टीथ्रेडिंगमध्ये Java थ्रेड प्राधान्य .

धागा तयार करत आहे

दस्तऐवजीकरणात सांगितल्याप्रमाणे, आमच्याकडे थ्रेड तयार करण्याचे 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(). या पद्धतींमध्ये गोंधळ घालू नका: जर आपण un()थेट r पद्धतीला कॉल केला तर कोणताही नवीन धागा सुरू होणार नाही. ही 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();
    }
}
RunnableJava 1.8 पासून फंक्शनल इंटरफेस देखील आहे. यामुळे थ्रेडच्या कार्यासाठी आणखी सुंदर कोड लिहिणे शक्य होते:

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

निष्कर्ष

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