थ्रेड पूलचा आणखी एक प्रकार "कॅशेड" आहे. असे थ्रेड पूल सामान्यतः निश्चित केलेल्या प्रमाणेच वापरले जातात.
नावाने दर्शविल्याप्रमाणे, या प्रकारचा थ्रेड पूल थ्रेड्स कॅश करतो. नवीन कार्ये करण्यासाठी ते थ्रेड्स पुन्हा वापरण्यासाठी ते मर्यादित काळासाठी न वापरलेले थ्रेड्स जिवंत ठेवतात. जेव्हा आपल्याकडे काही वाजवी प्रमाणात हलके काम असते तेव्हा असा थ्रेड पूल सर्वोत्तम असतो.
"काही वाजवी रक्कम" चा अर्थ ऐवजी विस्तृत आहे, परंतु तुम्हाला हे माहित असले पाहिजे की असा पूल प्रत्येक कामासाठी योग्य नाही. उदाहरणार्थ, समजा आपल्याला एक दशलक्ष कार्ये तयार करायची आहेत. जरी प्रत्येकाला खूप कमी वेळ लागतो, तरीही आम्ही संसाधनांचा अवास्तव वापर करू आणि कार्यप्रदर्शन खराब करू. जेव्हा अंमलबजावणीची वेळ अप्रत्याशित असते, उदाहरणार्थ, I/O कार्यांसह आपण असे पूल टाळले पाहिजेत.
हुड अंतर्गत, ThreadPoolExecutor कन्स्ट्रक्टरला खालील युक्तिवादांसह कॉल केला जातो:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
खालील मूल्ये वितर्क म्हणून कन्स्ट्रक्टरला दिली जातात:
पॅरामीटर | मूल्य |
---|---|
corePoolSize ( एक्झिक्युटर सेवा सुरू झाल्यावर किती थ्रेड तयार होतील (सुरू) | 0 |
MaxPoolSize ( एक्झिक्युटर सेवा तयार करू शकणार्या थ्रेडची कमाल संख्या ) | पूर्णांक.MAX_VALUE |
KeepAliveTime ( कोरपूलसाईज पेक्षा थ्रेड्सची संख्या जास्त असल्यास नष्ट होण्याआधी मोकळा केलेला थ्रेड जिवंत राहण्याची वेळ ) | 60L |
एकक (वेळेची एकके) | TimeUnit.SECONDS |
कार्य रांग (रांगेची अंमलबजावणी) | नवीन सिंक्रोनस रांग<Runnable>() |
आणि आम्ही थ्रेडफॅक्टरी ची स्वतःची अंमलबजावणी अगदी त्याच प्रकारे पास करू शकतो.
SynchronousQueue बद्दल बोलूया
सिंक्रोनस ट्रान्सफरची मूळ कल्पना अगदी सोपी आहे आणि तरीही काउंटर-इंटुटिव्ह आहे (म्हणजे अंतर्ज्ञान किंवा अक्कल तुम्हाला सांगते की ते चुकीचे आहे): तुम्ही रांगेत एक घटक जोडू शकता आणि जर दुसर्या थ्रेडला हा घटक मिळाला तरच . एकाच वेळी. दुसऱ्या शब्दांत, सिंक्रोनस रांगेत कार्ये असू शकत नाहीत, कारण नवीन कार्य येताच, कार्यान्वित करणार्या थ्रेडने आधीच कार्य उचलले आहे .
जेव्हा एखादे नवीन कार्य रांगेत प्रवेश करते, जर पूलमध्ये एक विनामूल्य सक्रिय धागा असेल तर ते कार्य उचलते. जर सर्व धागे व्यस्त असतील तर एक नवीन धागा तयार होतो.
कॅशे केलेला पूल शून्य थ्रेडसह सुरू होतो आणि संभाव्यत: Integer.MAX_VALUE थ्रेडपर्यंत वाढू शकतो. मूलत:, कॅश्ड थ्रेड पूलचा आकार केवळ सिस्टम संसाधनांद्वारे मर्यादित आहे.
सिस्टम संसाधने जतन करण्यासाठी, कॅश्ड थ्रेड पूल एका मिनिटासाठी निष्क्रिय असलेले थ्रेड काढून टाकतात.
चला सराव मध्ये ते कसे कार्य करते ते पाहूया. आम्ही एक टास्क क्लास तयार करू जो वापरकर्त्याच्या विनंतीचे मॉडेल करतो:
public class Task implements Runnable {
int taskNumber;
public Task(int taskNumber) {
this.taskNumber = taskNumber;
}
@Override
public void run() {
System.out.println("Processed user request #" + taskNumber + " on thread " + Thread.currentThread().getName());
}
}
मुख्य पद्धतीमध्ये , आम्ही नवीन कॅशेडथ्रेडपूल तयार करतो आणि नंतर अंमलबजावणीसाठी 3 कार्ये जोडतो. येथे आम्ही आमच्या सेवेची स्थिती मुद्रित करतो (1) .
पुढे, आम्ही 30 सेकंदांसाठी विराम देतो, दुसरे कार्य सुरू करतो आणि स्थिती प्रदर्शित करतो (2) .
त्यानंतर, आम्ही आमच्या मुख्य थ्रेडला 70 सेकंदांसाठी विराम देतो, स्थिती (3) प्रिंट करतो, नंतर पुन्हा 3 कार्ये जोडतो आणि पुन्हा स्थिती (4) मुद्रित करतो .
ज्या ठिकाणी आम्ही कार्य जोडल्यानंतर लगेच स्थिती प्रदर्शित करतो, आम्ही अद्ययावत आउटपुटसाठी प्रथम 1-सेकंद स्लीप जोडतो.
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 3; i++) {
executorService.submit(new Task(i));
}
TimeUnit.SECONDS.sleep(1);
System.out.println(executorService); //(1)
TimeUnit.SECONDS.sleep(30);
executorService.submit(new Task(3));
TimeUnit.SECONDS.sleep(1);
System.out.println(executorService); //(2)
TimeUnit.SECONDS.sleep(70);
System.out.println(executorService); //(3)
for (int i = 4; i < 7; i++) {
executorService.submit(new Task(i));
}
TimeUnit.SECONDS.sleep(1);
System.out.println(executorService); //(4)
executorService.shutdown();
आणि येथे परिणाम आहे:
प्रक्रिया केलेली वापरकर्ता विनंती #
0
.ThreadPoolExecutor@f6f4d33[चालत आहे, पूल आकार = 3, सक्रिय थ्रेड्स = 0, रांगेत कार्य = 0, पूर्ण केलेली कार्ये = 3]
प्रक्रिया केलेली वापरकर्ता विनंती #3 pool-1-thread-2 थ्रेड
(2) java.util.concurrent वर. ThreadPoolExecutor@f6f4d33[चालत आहे, पूल आकार = 3, सक्रिय थ्रेड = 0, रांगेत कार्य = 0, पूर्ण केलेली कार्ये = 4]
(3) java.util.concurrent.ThreadPoolExecutor@f6f4d33[चालू, पूल आकार = 0 सक्रिय , रांगेत असलेली कार्ये = 0, पूर्ण केलेली कार्ये = 4]
पूल-1-थ्रेड-4 थ्रेडवर प्रक्रिया केलेली वापरकर्ता विनंती #4
पूल-1-थ्रेड-5 थ्रेडवर प्रक्रिया केलेली वापरकर्ता विनंती #5
pool-1-thread-4 थ्रेड (4) java.util.concurrent.ThreadPoolExecutor@f6f4d33[चालू, पूल आकार = 2, सक्रिय थ्रेड्स = 0, रांगेत कार्ये = 0, पूर्ण केलेली कार्ये = 7] वर प्रक्रिया केलेली वापरकर्ता विनंती #6
चला प्रत्येक पायरीवर जाऊया:
पाऊल | स्पष्टीकरण |
---|---|
1 (3 पूर्ण केलेल्या कार्यांनंतर) | आम्ही 3 थ्रेड तयार केले आणि या तीन थ्रेडवर 3 कार्ये पूर्ण केली. जेव्हा स्थिती प्रदर्शित होते, तेव्हा सर्व 3 कार्ये पूर्ण होतात आणि थ्रेड इतर कार्ये करण्यासाठी तयार असतात. |
2 (30-सेकंदाच्या विरामानंतर आणि दुसर्या कार्याची अंमलबजावणी) | 30 सेकंदांच्या निष्क्रियतेनंतर, थ्रेड अद्याप जिवंत आहेत आणि कार्यांची प्रतीक्षा करत आहेत. उर्वरित थेट थ्रेड्सच्या पूलमधून घेतलेल्या थ्रेडवर आणखी एक कार्य जोडले आणि अंमलात आणले. पूलमध्ये कोणताही नवीन धागा जोडला गेला नाही. |
3 (70-सेकंदाच्या विरामानंतर) | पूलमधून धागे काढले आहेत. कार्ये स्वीकारण्यासाठी कोणतेही धागे तयार नाहीत. |
4 (आणखी 3 कार्ये पूर्ण केल्यानंतर) | अधिक कार्ये प्राप्त झाल्यानंतर, नवीन धागे तयार केले गेले. यावेळी फक्त दोन थ्रेड्स 3 कार्यांवर प्रक्रिया करण्यात व्यवस्थापित झाले. |
बरं, आता तुम्ही दुसऱ्या प्रकारच्या एक्झिक्यूटर सेवेच्या तर्काशी परिचित आहात.
एक्झिक्युटर्स युटिलिटी क्लासच्या इतर पद्धतींशी साधर्म्य साधून , नवीन कॅशेडथ्रेडपूल पद्धतीमध्ये एक ओव्हरलोड आवृत्ती देखील आहे जी थ्रेडफॅक्टरी ऑब्जेक्टला युक्तिवाद म्हणून घेते.
GO TO FULL VERSION