हाय! जेव्हा तुम्ही CodeGym वर मल्टीथ्रेडिंगचा अभ्यास केला, तेव्हा तुम्हाला "म्युटेक्स" आणि "मॉनिटर" या संकल्पनांचा वारंवार सामना करावा लागला. डोकावल्याशिवाय, ते कसे वेगळे आहेत ते तुम्ही सांगू शकता? :) होय असल्यास, चांगले केले! नसल्यास (हे सर्वात सामान्य आहे), यात आश्चर्य नाही. "म्युटेक्स" आणि "मॉनिटर" या प्रत्यक्षात संबंधित संकल्पना आहेत. याव्यतिरिक्त, जेव्हा तुम्ही धडे वाचता आणि इतर वेबसाइटवर मल्टीथ्रेडिंगबद्दल व्हिडिओ पाहता तेव्हा तुम्हाला आणखी एक समान संकल्पना आढळेल: "सेमाफोर". त्याचे मॉनिटर्स आणि म्यूटेक्स सारखे कार्य देखील आहे. म्हणूनच आम्ही या तीन संज्ञा तपासणार आहोत. आम्ही काही उदाहरणे पाहू आणि या संकल्पना एकमेकांपासून कशा वेगळ्या आहेत हे निश्चितपणे समजून घेऊ :)
म्युटेक्स
म्युटेक्स (किंवा लॉक) ही थ्रेड्स सिंक्रोनाइझ करण्यासाठी एक विशेष यंत्रणा आहे. Java मधील प्रत्येक ऑब्जेक्टशी एक "संलग्न" आहे — तुम्हाला हे आधीच माहित आहे :) तुम्ही मानक वर्ग वापरत असाल किंवा तुमचे स्वतःचे वर्ग तयार केले तर काही फरक पडत नाही, उदा. मांजर आणि कुत्रा : सर्व वर्गांच्या सर्व वस्तूंना म्युटेक्स असते . "म्युटेक्स" हा शब्द "म्युच्युअल एक्सक्लूजन" वरून आला आहे, जो त्याच्या उद्देशाचे अचूक वर्णन करतो. आम्ही आमच्या मागील धड्यांपैकी एकामध्ये म्हटल्याप्रमाणे, म्युटेक्स हे सुनिश्चित करणे शक्य करते की एका वेळी फक्त एका थ्रेडला ऑब्जेक्टमध्ये प्रवेश आहे. म्युटेक्सचे लोकप्रिय वास्तविक जीवन उदाहरण म्हणजे शौचालये. जेव्हा एखादी व्यक्ती टॉयलेट पार्टीशनमध्ये प्रवेश करते तेव्हा तो दरवाजा आतून बंद करतो. शौचालय हे एका वस्तूसारखे आहे ज्यामध्ये अनेक थ्रेड्सद्वारे प्रवेश केला जाऊ शकतो. विभाजनाच्या दरवाजावरील लॉक म्यूटेक्ससारखे आहे आणि बाहेरील लोकांची ओळ थ्रेड्स दर्शवते. दरवाजावरील कुलूप हे शौचालयाचे म्युटेक्स आहे: हे सुनिश्चित करते की फक्त एक व्यक्ती आत जाऊ शकते. दुसऱ्या शब्दांत, एका वेळी फक्त एक धागा सामायिक संसाधनांसह कार्य करू शकतो. व्यापलेल्या संसाधनांमध्ये प्रवेश मिळवण्यासाठी इतर धाग्यांचे (लोकांचे) प्रयत्न अयशस्वी होतील. म्युटेक्समध्ये अनेक महत्त्वाची वैशिष्ट्ये आहेत. प्रथम , फक्त दोन अवस्था शक्य आहेत: "अनलॉक केलेले" आणि "लॉक केलेले". हे आम्हाला ते कसे कार्य करते हे समजण्यास मदत करते: तुम्ही बुलियन व्हेरिएबल्स (सत्य/असत्य) किंवा बायनरी संख्या (0/1) सह समांतर काढू शकता. राज्यावर थेट नियंत्रण ठेवता येत नाही. Java कडे कोणतीही यंत्रणा नाही जी तुम्हाला एखादी वस्तू स्पष्टपणे घेऊ देते, त्याचे म्यूटेक्स मिळवू देते आणि इच्छित स्थिती नियुक्त करू देते. दुसऱ्या शब्दांत, तुम्ही असे काही करू शकत नाही:
Object myObject = new Object();
Mutex mutex = myObject.getMutex();
mutex.free();
याचा अर्थ असा की तुम्ही ऑब्जेक्टचे म्युटेक्स सोडू शकत नाही. फक्त जावा मशीनला त्यात थेट प्रवेश आहे. प्रोग्रामर भाषेच्या साधनांद्वारे म्यूटेक्ससह कार्य करतात.
मॉनिटर
मॉनिटर हा म्युटेक्सवर अतिरिक्त "सुपरस्ट्रक्चर" असतो. खरं तर, मॉनिटर हा कोडचा एक भाग आहे जो प्रोग्रामरसाठी "अदृश्य" असतो. जेव्हा आम्ही आधी म्यूटेक्सबद्दल बोललो तेव्हा आम्ही एक साधे उदाहरण दिले:
public class Main {
private Object obj = new Object();
public void doSomething() {
// ...some logic, available for all threads
synchronized (obj) {
// Logic available to just one thread at a time
}
}
}
सिंक्रोनाइझ केलेल्या कीवर्डसह चिन्हांकित केलेल्या कोड ब्लॉकमध्ये , आमच्या obj ऑब्जेक्टचे म्यूटेक्स घेतले जाते. छान, आम्ही लॉक मिळवू शकतो, परंतु "संरक्षण" नक्की कसे दिले जाते? जेव्हा आपण शब्द समक्रमित पाहतो , तेव्हा इतर थ्रेड्सला ब्लॉकमध्ये प्रवेश करण्यापासून काय प्रतिबंधित करते? संरक्षण मॉनिटरवरून येते! कंपाइलर सिंक्रोनाइझ केलेल्या कीवर्डला कोडच्या अनेक विशेष तुकड्यांमध्ये रूपांतरित करतो. पुन्हा एकदा, doSomething() पद्धतीसह आपल्या उदाहरणाकडे परत येऊ . आम्ही त्यात जोडू:
public class Main {
private Object obj = new Object();
public void doSomething() {
// ...some logic, available for all threads
// Logic available to just one thread at a time
synchronized (obj) {
/* Do important work that requires that the object
be accessed by only one thread */
obj.someImportantMethod();
}
}
}
कंपाइलरने हा कोड रूपांतरित केल्यानंतर "अंडर द हुड" काय होते ते येथे आहे:
public class Main {
private Object obj = new Object();
public void doSomething() throws InterruptedException {
// ...some logic, available for all threads
// Logic available to just one thread at a time:
/* as long as the object's mutex is busy,
all the other threads (except the one that acquired it) are put to sleep */
while (obj.getMutex().isBusy()) {
Thread.sleep(1);
}
// Mark the object's mutex as busy
obj.getMutex().isBusy() = true;
/* Do important work that requires that the object
be accessed by only one thread */
obj.someImportantMethod();
// Free the object's mutex
obj.getMutex().isBusy() = false;
}
}
अर्थात, हे खरे उदाहरण नाही. येथे, आम्ही Java मशीनमध्ये काय घडते ते चित्रित करण्यासाठी Java-सारखा कोड वापरला आहे. असे म्हटले आहे की, हा स्यूडो-कोड सिंक्रोनाइझ ब्लॉकमधील ऑब्जेक्ट आणि थ्रेड्ससह प्रत्यक्षात काय होते आणि कंपायलर या कीवर्डला प्रोग्रामरसाठी "अदृश्य" असलेल्या अनेक विधानांमध्ये कसे रूपांतरित करतो याची उत्कृष्ट समज देतो. मूलतः, जावा मॉनिटरचे प्रतिनिधित्व करण्यासाठी सिंक्रोनाइझ केलेला कीवर्ड वापरतो . शेवटच्या उदाहरणात सिंक्रोनाइझ केलेल्या कीवर्डऐवजी दिसणारे सर्व कोड मॉनिटर आहे.
सेमाफोर
मल्टीथ्रेडिंगच्या तुमच्या वैयक्तिक अभ्यासात तुम्हाला आढळणारा दुसरा शब्द म्हणजे "सेमाफोर". हे काय आहे आणि ते मॉनिटर आणि म्यूटेक्सपेक्षा कसे वेगळे आहे ते शोधूया. सेमाफोर हे काही स्त्रोतांमध्ये प्रवेश समक्रमित करण्यासाठी एक साधन आहे. त्याचे विशिष्ट वैशिष्ट्य म्हणजे ते सिंक्रोनाइझेशन यंत्रणा तयार करण्यासाठी काउंटर वापरते. काउंटर आम्हाला सांगते की किती थ्रेड्स एकाच वेळी सामायिक संसाधनात प्रवेश करू शकतात. Java मधील Semaphores हे Semaphore वर्गाद्वारे दर्शविले जाते. सेमाफोर ऑब्जेक्ट्स तयार करताना, आपण खालील कन्स्ट्रक्टर वापरू शकतो:
Semaphore(int permits)
Semaphore(int permits, boolean fair)
आम्ही खालील गोष्टी कन्स्ट्रक्टरला देतो:
- बुलियन फेअर — ज्या क्रमाने थ्रेड्सना प्रवेश मिळेल ते स्थापित करते. जर वाजवी सत्य असेल, तर त्यांनी विनंती केलेल्या क्रमाने वेटिंग थ्रेड्सना प्रवेश दिला जातो. जर ते खोटे असेल तर थ्रेड शेड्यूलरद्वारे ऑर्डर निश्चित केली जाते.
class Philosopher extends Thread {
private Semaphore sem;
// Did the philosopher eat?
private boolean full = false;
private String name;
Philosopher(Semaphore sem, String name) {
this.sem=sem;
this.name=name;
}
public void run()
{
try
{
// If the philosopher has not eaten
if (!full) {
// Ask the semaphore for permission to run
sem.acquire();
System.out.println(name + " takes a seat at the table");
// The philosopher eats
sleep(300);
full = true;
System.out.println(name + " has eaten! He leaves the table");
sem.release();
// The philosopher leaves, making room for others
sleep(300);
}
}
catch(InterruptedException e) {
System.out.println("Something went wrong!");
}
}
}
आणि आमचा प्रोग्राम चालवण्याचा कोड येथे आहे:
public class Main {
public static void main(String[] args) {
Semaphore sem = new Semaphore(2);
new Philosopher(sem, "Socrates").start();
new Philosopher(sem,"Plato").start();
new Philosopher(sem,"Aristotle").start();
new Philosopher(sem, "Thales").start();
new Philosopher(sem, "Pythagoras").start();
}
}
आम्ही एक सेमाफोर तयार केला आहे ज्याचे काउंटर 2 वर सेट केले आहे स्थिती पूर्ण करण्यासाठी: फक्त दोन तत्त्वज्ञ एकाच वेळी खाऊ शकतात. म्हणजेच, एकाच वेळी फक्त दोनच धागे चालू शकतात, कारण आमच्या फिलॉसॉफर वर्गाला थ्रेडचा वारसा मिळाला आहे ! Semaphore वर्गाच्या acquire () आणि release() पद्धती त्याच्या ऍक्सेस काउंटरवर नियंत्रण ठेवतात. acquire() पद्धत सेमाफोरला रिसोर्समध्ये प्रवेशासाठी विचारते. काउंटर >0 असल्यास, प्रवेश मंजूर केला जातो आणि काउंटर 1 ने कमी केला जातो. रिलीज ()पद्धत पूर्वी मंजूर केलेला प्रवेश "रिलीज" करते, काउंटरवर परत करते (सेमाफोरचा प्रवेश काउंटर 1 ने वाढवते). जेव्हा आपण प्रोग्राम चालवतो तेव्हा आपल्याला काय मिळते? समस्या सुटली आहे का? आपल्या पाळी येण्याची वाट पाहत आपले तत्त्वज्ञ लढणार नाहीत का? :) आम्हाला मिळालेले कन्सोल आउटपुट येथे आहे:
Socrates takes a seat at the table
Plato takes a seat at the table
Socrates has eaten! He leaves the table
Plato has eaten! He leaves the table
Aristotle takes a seat at the table
Pythagoras takes a seat at the table
Aristotle has eaten! He leaves the table
Pythagoras has eaten! He leaves the table
Thales takes a seat at the table
Thales has eaten! He leaves the table
आम्ही ते केले! आणि थॅलेसला एकट्याने जेवण करावे लागले असले तरी, मला वाटत नाही की आम्ही त्याला नाराज केले आहे :) तुम्हाला म्युटेक्स आणि सेमाफोरमध्ये काही साम्य आढळले असेल. खरंच, त्यांचे एकच ध्येय आहे: काही संसाधनांमध्ये प्रवेश समक्रमित करणे. फरक एवढाच आहे की ऑब्जेक्टचे म्युटेक्स एका वेळी फक्त एका थ्रेडद्वारे प्राप्त केले जाऊ शकते, तर थ्रेड काउंटर वापरणाऱ्या सेमफोरच्या बाबतीत, अनेक थ्रेड्स एकाच वेळी संसाधनात प्रवेश करू शकतात. हा निव्वळ योगायोग नाही :) म्युटेक्स हा सेमाफोर आहे1 च्या गणनेसह. दुसऱ्या शब्दांत, हा एक सेमफोर आहे जो एकच धागा सामावून घेऊ शकतो. याला "बायनरी सेमाफोर" म्हणून देखील ओळखले जाते कारण त्याच्या काउंटरमध्ये फक्त 2 मूल्ये असू शकतात - 1 ("अनलॉक केलेले") आणि 0 ("लॉक केलेले"). बस एवढेच! तुम्ही बघू शकता, हे इतके गोंधळात टाकणारे नाही :) आता, जर तुम्हाला इंटरनेटवर मल्टीथ्रेडिंगचा अधिक तपशीलवार अभ्यास करायचा असेल, तर तुमच्यासाठी या संकल्पनांवर नेव्हिगेट करणे थोडे सोपे होईल. पुढील धड्यांमध्ये भेटू!
GO TO FULL VERSION