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

एकत्र चांगले: Java आणि थ्रेड वर्ग. भाग VI - आग दूर!

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

परिचय

धागे ही एक मनोरंजक गोष्ट आहे. मागील पुनरावलोकनांमध्ये, आम्ही मल्टीथ्रेडिंग लागू करण्यासाठी काही उपलब्ध साधने पाहिली. आपण इतर कोणत्या मनोरंजक गोष्टी करू शकतो ते पाहूया. या क्षणी, आम्हाला बरेच काही माहित आहे. उदाहरणार्थ, " Better together: Java and the थ्रेड क्लास. भाग I — थ्रेड्स ऑफ एक्झिक्यूशन " मधून, आम्हाला माहित आहे की थ्रेड क्लास एक्झिक्युशनचा एक धागा दर्शवतो. आम्हाला माहित आहे की धागा काही कार्य करतो. जर आम्हाला आमची कार्ये सक्षम व्हायची असतील runतर आम्ही थ्रेड सह चिन्हांकित करणे आवश्यक आहे Runnable. लक्षात ठेवण्यासाठी, आपण Tutorialspoint Online Java Compilerएकत्र चांगले: Java आणि थ्रेड वर्ग.  भाग VI - आग दूर!  - १ वापरू शकतो :

public static void main(String[] args){
	Runnable task = () -> {
 		Thread thread = Thread.currentThread();
		System.out.println("Hello from " + thread.getName());
	};
	Thread thread = new Thread(task);
	thread.start();
}
आपल्याला हे देखील माहित आहे की आपल्याकडे लॉक नावाची काहीतरी आहे. आम्ही याबद्दल " एकत्र चांगले: Java आणि थ्रेड वर्ग. भाग II — सिंक्रोनाइझेशन. मध्ये शिकलो . जर एका थ्रेडने लॉक प्राप्त केले, तर लॉक मिळवण्याचा प्रयत्न करणार्‍या दुसर्‍या थ्रेडला लॉक रिलीझ होण्याची प्रतीक्षा करण्यास भाग पाडले जाईल:

import java.util.concurrent.locks.*;

public class HelloWorld{
	public static void main(String []args){
		Lock lock = new ReentrantLock();
		Runnable task = () -> {
			lock.lock();
			Thread thread = Thread.currentThread();
			System.out.println("Hello from " + thread.getName());
			lock.unlock();
		};
		Thread thread = new Thread(task);
		thread.start();
	}
}
मला वाटते की आपण इतर कोणत्या मनोरंजक गोष्टी करू शकतो याबद्दल बोलण्याची वेळ आली आहे.

सेमाफोर्स

एकाच वेळी किती धागे चालू शकतात हे नियंत्रित करण्याचा सर्वात सोपा मार्ग म्हणजे सेमाफोर. हे रेल्वे सिग्नलसारखे आहे. हिरवा म्हणजे पुढे जा. लाल म्हणजे थांबा. Semaphore पासून काय प्रतीक्षा? प्रवेश. प्रवेश मिळविण्यासाठी, आपण ते प्राप्त केले पाहिजे. आणि जेव्हा यापुढे प्रवेशाची आवश्यकता नसते, तेव्हा आपण ते दिले पाहिजे किंवा सोडले पाहिजे. हे कसे कार्य करते ते पाहूया. आम्हाला वर्ग आयात करणे आवश्यक आहे java.util.concurrent.Semaphore. उदाहरण:

public static void main(String[] args) throws InterruptedException {
	Semaphore semaphore = new Semaphore(0);
	Runnable task = () -> {
		try {
			semaphore.acquire();
			System.out.println("Finished");
			semaphore.release();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	};
	new Thread(task).start();
	Thread.sleep(5000);
	semaphore.release(1);
}
जसे तुम्ही बघू शकता, सेमाफोर कसे कार्य करते हे समजून घेण्यासाठी या ऑपरेशन्स (अधिग्रहित करणे आणि सोडणे) आम्हाला मदत करतात. सर्वात महत्वाची गोष्ट अशी आहे की जर आपल्याला प्रवेश मिळवायचा असेल, तर सेमाफोरकडे परवान्यांची सकारात्मक संख्या असणे आवश्यक आहे. ही गणना ऋण संख्येवर सुरू केली जाऊ शकते. आणि आम्ही 1 पेक्षा जास्त परमिटची विनंती करू शकतो.

CountDownLatch

पुढील यंत्रणा आहे CountDownLatch. आश्चर्याची गोष्ट म्हणजे, ही काउंटडाउन असलेली कुंडी आहे. येथे आपल्याला वर्गासाठी योग्य आयात विधान आवश्यक आहे java.util.concurrent.CountDownLatch. हे पायांच्या शर्यतीसारखे आहे, जिथे प्रत्येकजण सुरुवातीच्या ओळीवर एकत्र येतो. आणि एकदा प्रत्येकजण तयार झाल्यावर, प्रत्येकाला एकाच वेळी प्रारंभिक सिग्नल प्राप्त होतो आणि एकाच वेळी प्रारंभ होतो. उदाहरण:

public static void main(String[] args) {
	CountDownLatch countDownLatch = new CountDownLatch(3);
	Runnable task = () -> {
		try {
			countDownLatch.countDown();
			System.out.println("Countdown: " + countDownLatch.getCount());
			countDownLatch.await();
			System.out.println("Finished");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	};
	for (int i = 0; i < 3; i++) {
		new Thread(task).start();
 	}
}
प्रथम, आम्ही प्रथम कुंडीला सांगतो countDown(). गुगल काउंटडाउनची व्याख्या "शून्य करण्यासाठी उलट क्रमाने संख्या मोजण्याची क्रिया" म्हणून करते. आणि मग आपण लॅच ला सांगतो await(), म्हणजे काउंटर शून्य होईपर्यंत थांबा. विशेष म्हणजे हे एकवेळचे काउंटर आहे. जावा डॉक्युमेंटेशन म्हणते, "जेव्हा थ्रेड्स वारंवार अशा प्रकारे मोजणे आवश्यक आहे, त्याऐवजी CyclicBarrier वापरा". दुसऱ्या शब्दांत, तुम्हाला पुन्हा वापरता येण्याजोग्या काउंटरची आवश्यकता असल्यास, तुम्हाला वेगळ्या पर्यायाची आवश्यकता आहे: CyclicBarrier.

सायकलबॅरियर

नावाप्रमाणेच, CyclicBarrierएक "पुन्हा वापरण्यायोग्य" अडथळा आहे. आम्हाला वर्ग आयात करावा लागेल java.util.concurrent.CyclicBarrier. चला एक उदाहरण पाहू:

public static void main(String[] args) throws InterruptedException {
	Runnable action = () -> System.out.println("On your mark!");
	CyclicBarrier barrier = new CyclicBarrier(3, action);
	Runnable task = () -> {
		try {
			barrier.await();
			System.out.println("Finished");
		} catch (BrokenBarrierException | InterruptedException e) {
			e.printStackTrace();
		}
	};
	System.out.println("Limit: " + barrier.getParties());
	for (int i = 0; i < 3; i++) {
		new Thread(task).start();
	}
}
जसे आपण पाहू शकता, थ्रेड awaitपद्धत चालवते, म्हणजे ती प्रतीक्षा करते. या प्रकरणात, अडथळा मूल्य कमी होते. barrier.isBroken()जेव्हा काउंटडाउन शून्यावर पोहोचते तेव्हा अडथळा ( ) तुटलेला मानला जातो . अडथळा रीसेट करण्यासाठी, आपल्याला reset()पद्धत कॉल करणे आवश्यक आहे, ज्यामध्ये CountDownLatchनाही.

एक्सचेंजर

पुढील यंत्रणा म्हणजे एक्सचेंजर. या संदर्भात, एक्सचेंज हा एक सिंक्रोनाइझेशन पॉइंट आहे जेथे बदललेल्या गोष्टींची देवाणघेवाण किंवा अदलाबदल केली जाते. तुमच्या अपेक्षेप्रमाणे, एक Exchangerहा वर्ग आहे जो एक्सचेंज किंवा स्वॅप करतो. चला सर्वात सोपं उदाहरण पाहू:

public static void main(String[] args) {
	Exchanger<String> exchanger = new Exchanger<>();
	Runnable task = () -> {
		try {
			Thread thread = Thread.currentThread();
			String withThreadName = exchanger.exchange(thread.getName());
			System.out.println(thread.getName() + " exchanged with " + withThreadName);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	};
	new Thread(task).start();
	new Thread(task).start();
}
येथे आपण दोन धागे सुरू करतो. त्यापैकी प्रत्येक एक्सचेंज पद्धत चालवतो आणि इतर थ्रेडची देखील एक्सचेंज पद्धत चालवण्याची प्रतीक्षा करतो. असे केल्याने, थ्रेड पास झालेल्या युक्तिवादांची देवाणघेवाण करतात. मनोरंजक. हे तुम्हाला काहीतरी आठवण करून देत नाही का? हे ची आठवण करून देणारे आहे SynchronousQueue, जे च्या हृदयात आहे CachedThreadPool. स्पष्टतेसाठी, येथे एक उदाहरण आहे:

public static void main(String[] args) throws InterruptedException {
	SynchronousQueue<String> queue = new SynchronousQueue<>();
	Runnable task = () -> {
		try {
			System.out.println(queue.take());
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	};
	new Thread(task).start();
	queue.put("Message");
}
उदाहरण दर्शविते की जेव्हा नवीन धागा सुरू केला जातो तेव्हा तो प्रतीक्षा करेल, कारण रांग रिकामी असेल. आणि मग मुख्य थ्रेड रांगेत "संदेश" स्ट्रिंग ठेवतो. इतकेच काय, रांगेतून ही स्ट्रिंग मिळेपर्यंत ते थांबेल. या विषयाबद्दल अधिक जाणून घेण्यासाठी तुम्ही " SynchronousQueue vs Exchanger " देखील वाचू शकता.

फेसर

आम्ही शेवटच्यासाठी सर्वोत्तम जतन केले आहे — Phaser. आम्हाला वर्ग आयात करावा लागेल java.util.concurrent.Phaser. चला एक साधे उदाहरण पाहू:

public static void main(String[] args) throws InterruptedException {
        Phaser phaser = new Phaser();
        // By calling the register method, we register the current (main) thread as a party
        phaser.register();
        System.out.println("Phasecount is " + phaser.getPhase());
        testPhaser(phaser);
        testPhaser(phaser);
        testPhaser(phaser);
        // After 3 seconds, we arrive at the barrier and deregister. Number of arrivals = number of registrations = start
        Thread.sleep(3000);
        phaser.arriveAndDeregister();
        System.out.println("Phasecount is " + phaser.getPhase());
    }

    private static void testPhaser(final Phaser phaser) {
        // We indicate that there will be a +1 party on the Phaser
        phaser.register();
        // Start a new thread
        new Thread(() -> {
            String name = Thread.currentThread().getName();
            System.out.println(name + " arrived");
            phaser.arriveAndAwaitAdvance(); // The threads register arrival at the phaser.
            System.out.println(name + " after passing barrier");
        }).start();
    }
उदाहरण स्पष्ट करते की वापरताना Phaser, जेव्हा नोंदणीची संख्या अडथळ्यावरील आगमनांच्या संख्येशी जुळते तेव्हा अडथळा तुटतो. आपण हा GeeksforGeeks लेखPhaser वाचून अधिक परिचित होऊ शकता .

सारांश

तुम्ही या उदाहरणांवरून पाहू शकता, थ्रेड्स सिंक्रोनाइझ करण्याचे विविध मार्ग आहेत. यापूर्वी, मी मल्टीथ्रेडिंगचे पैलू आठवण्याचा प्रयत्न केला. मला आशा आहे की या मालिकेतील मागील हप्ते उपयुक्त असतील. काही लोक म्हणतात की मल्टीथ्रेडिंगचा मार्ग "जावा कॉन्करन्सी इन प्रॅक्टिस" या पुस्तकापासून सुरू होतो. जरी ते 2006 मध्ये प्रसिद्ध झाले असले तरी, लोक म्हणतात की हे पुस्तक बरेच मूलभूत आणि आजही संबंधित आहे. उदाहरणार्थ, तुम्ही येथे चर्चा वाचू शकता: "Java Concurrency In Practice" अजूनही वैध आहे का? . चर्चेतील दुवे वाचणे देखील उपयुक्त आहे. उदाहरणार्थ, The Well-Grounded Java Developer या पुस्तकाची लिंक आहे आणि आम्ही Chapter 4. आधुनिक concurrency चा विशेष उल्लेख करू . या विषयावर संपूर्ण पुनरावलोकन देखील आहे:जावा 8 च्या युगात "जावा कॉन्करन्सी इन प्रॅक्टिस" अजूनही वैध आहे का? हा विषय खऱ्या अर्थाने समजून घेण्यासाठी आणखी काय वाचावे याबद्दलही तो लेख सूचना देतो. त्यानंतर, तुम्ही OCA/OCP Java SE 8 Programmer Practice Tests सारखे उत्तम पुस्तक पाहू शकता . आम्हाला दुसऱ्या संक्षेपात स्वारस्य आहे: OCP (Oracle Certified Professional). तुम्हाला "चॅप्टर 20: जावा कॉन्करन्सी" मध्ये चाचण्या सापडतील. या पुस्तकात स्पष्टीकरणासह प्रश्न आणि उत्तरे दोन्ही आहेत. उदाहरणार्थ: एकत्र चांगले: Java आणि थ्रेड वर्ग.  भाग VI - आग दूर!  - 3बरेच लोक असे म्हणू लागतील की हा प्रश्न पद्धती लक्षात ठेवण्याचे आणखी एक उदाहरण आहे. एकीकडे, होय. दुसरीकडे, तुम्ही या प्रश्नाचे उत्तर स्मरण करून देऊ शकता की ते ExecutorServiceएक प्रकारचे "अपग्रेड" आहे Executor. आणिExecutorथ्रेड कसे तयार केले जातात ते लपविण्याचा हेतू आहे, परंतु ते कार्यान्वित करण्याचा हा मुख्य मार्ग नाही, म्हणजे, Runnableनवीन थ्रेडवर ऑब्जेक्ट सुरू करणे. म्हणूनच तेथे नाही execute(Callable)— कारण मध्ये ExecutorService, Executorफक्त पद्धती जोडते submit()ज्या ऑब्जेक्ट परत करू शकतात Future. अर्थात, आम्ही पद्धतींची यादी लक्षात ठेवू शकतो, परंतु वर्गांच्या स्वरूपाच्या आमच्या ज्ञानावर आधारित आमचे उत्तर तयार करणे खूप सोपे आहे. आणि या विषयावरील काही अतिरिक्त साहित्य येथे आहेतः एकत्र चांगले: Java आणि थ्रेड वर्ग. भाग I — अंमलबजावणीचे धागे एकत्र चांगले: Java आणि थ्रेड क्लास. भाग II — एकत्रितपणे सिंक्रोनाइझेशन उत्तम: Java आणि थ्रेड वर्ग. भाग तिसरा — परस्परसंवाद चांगले एकत्र: Java आणि थ्रेड वर्ग. भाग IV — कॉल करण्यायोग्य, भविष्य आणि मित्र एकत्र चांगले: Java आणि थ्रेड वर्ग. भाग V — एक्झिक्युटर, थ्रेडपूल, फोर्क/जॉइन
टिप्पण्या
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION