एक अन्य प्रकार का थ्रेड पूल "कैश्ड" है। इस तरह के थ्रेड पूल आमतौर पर निश्चित रूप से उपयोग किए जाते हैं।

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

"कुछ उचित राशि" का अर्थ काफी व्यापक है, लेकिन आपको पता होना चाहिए कि ऐसा पूल हर कार्य के लिए उपयुक्त नहीं है। उदाहरण के लिए, मान लीजिए कि हम एक लाख कार्य बनाना चाहते हैं। यहां तक ​​कि अगर प्रत्येक बहुत कम समय लेता है, तब भी हम संसाधनों की अनुचित मात्रा का उपयोग करेंगे और प्रदर्शन को खराब करेंगे। निष्पादन समय अप्रत्याशित होने पर हमें ऐसे पूल से भी बचना चाहिए, उदाहरण के लिए, I/O कार्यों के साथ।

हुड के तहत, थ्रेडपूल एक्ज़ीक्यूटर कंस्ट्रक्टर को निम्नलिखित तर्कों के साथ बुलाया जाता है:

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,
      new SynchronousQueue<Runnable>());
}

निम्न मान कंस्ट्रक्टर को तर्क के रूप में पास किए जाते हैं:

पैरामीटर कीमत
corePoolSize ( निष्पादक सेवा शुरू होने पर कितने धागे तैयार होंगे (शुरू) ) 0
maxPoolSize (एक निष्पादक सेवा द्वारा बनाए जा सकने वाले थ्रेड्स की अधिकतम संख्या ) पूर्णांक.MAX_VALUE
KeepAliveTime (वह समय जब थ्रेड्स की संख्या corePoolSize से अधिक होने पर नष्ट होने से पहले एक मुक्त धागा जीवित रहेगा ) 60एल
इकाई (समय की इकाइयां) TimeUnit.SECONDS
वर्कक्यू (एक कतार का कार्यान्वयन) नया सिंक्रोनस क्यू <रननेबल> ()

और हम थ्रेडफैक्ट्री के अपने कार्यान्वयन को बिल्कुल उसी तरह पारित कर सकते हैं।

आइए सिंक्रोनस क्यू के बारे में बात करते हैं

एक तुल्यकालिक स्थानांतरण का मूल विचार काफी सरल और अभी तक प्रति-सहज ज्ञान युक्त है (यानी, अंतर्ज्ञान या सामान्य ज्ञान आपको बताता है कि यह गलत है): आप कतार में एक तत्व जोड़ सकते हैं यदि और केवल तभी जब कोई अन्य धागा तत्व प्राप्त करता है उसी समय। दूसरे शब्दों में, एक तुल्यकालिक कतार में कार्य नहीं हो सकते हैं, क्योंकि जैसे ही कोई नया कार्य आता है, निष्पादन थ्रेड पहले ही कार्य उठा चुका होता है

जब कोई नया कार्य कतार में प्रवेश करता है, यदि पूल में एक मुक्त सक्रिय धागा है, तो यह कार्य को चुन लेता है। यदि सभी थ्रेड्स व्यस्त हैं, तो एक नया थ्रेड बनाया जाता है।

एक कैश्ड पूल शून्य थ्रेड्स से शुरू होता है और संभावित रूप से 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());
   }
}

मुख्य विधि में , हम newCachedThreadPool बनाते हैं और फिर निष्पादन के लिए 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 पूल-1-थ्रेड-1 थ्रेड पर
संसाधित उपयोगकर्ता अनुरोध #1 पूल-1-थ्रेड-2 थ्रेड पर
संसाधित उपयोगकर्ता अनुरोध #2 पूल-1-थ्रेड-3 थ्रेड पर
(1) java.util.concurrent .ThreadPoolExecutor@f6f4d33 [चल रहा है, पूल आकार = 3, सक्रिय धागे = 0, कतारबद्ध कार्य = 0, पूर्ण कार्य = 3]
संसाधित उपयोगकर्ता अनुरोध #3 पूल-1-थ्रेड-2 थ्रेड
(2) java.util.concurrent पर। थ्रेडपूल एक्ज़ीक्यूटर@f6f4d33[चल रहा है, पूल आकार = 3, सक्रिय धागे = 0, कतारबद्ध कार्य = 0, पूर्ण कार्य = 4] (3) java.util.concurrent.ThreadPoolExecutor@f6f4d33 [चल रहा है, पूल आकार = 0, सक्रिय
धागे = 0 , कतारबद्ध कार्य = 0, पूर्ण कार्य = 4]
संसाधित उपयोगकर्ता अनुरोध #4 पूल-1-थ्रेड-4 थ्रेड पर
संसाधित उपयोगकर्ता अनुरोध #5 पूल-1-थ्रेड-5 थ्रेड पर
संसाधित उपयोगकर्ता अनुरोध #6 पूल-1-थ्रेड-4 थ्रेड पर
(4) java.util.concurrent.ThreadPoolExecutor@f6f4d33[चल रहा है, पूल आकार = 2, सक्रिय थ्रेड्स = 0, कतारबद्ध कार्य = 0, पूर्ण कार्य = 7]

आइए प्रत्येक चरण पर जाएं:

कदम व्याख्या
1 (3 पूर्ण कार्यों के बाद) हमने 3 थ्रेड्स बनाए, और इन तीन थ्रेड्स पर 3 कार्य निष्पादित किए गए।
जब स्थिति प्रदर्शित होती है, तो सभी 3 कार्य पूर्ण हो जाते हैं, और थ्रेड अन्य कार्य करने के लिए तैयार होते हैं।
2 (30 सेकंड के ठहराव और दूसरे कार्य के निष्पादन के बाद) 30 सेकंड की निष्क्रियता के बाद, थ्रेड्स अभी भी जीवित हैं और कार्यों की प्रतीक्षा कर रहे हैं।
शेष लाइव थ्रेड्स के पूल से लिए गए थ्रेड पर एक और कार्य जोड़ा और निष्पादित किया जाता है।
पूल में कोई नया धागा नहीं जोड़ा गया।
3 (70 सेकंड के विराम के बाद) तालाब से धागों को निकाल लिया गया है।
कार्यों को स्वीकार करने के लिए कोई थ्रेड तैयार नहीं है।
4 (3 और कार्य करने के बाद) अधिक कार्य प्राप्त होने के बाद, नए सूत्र बनाए गए। इस बार सिर्फ दो धागे 3 कार्यों को पूरा करने में कामयाब रहे।

ठीक है, अब आप एक अन्य प्रकार की निष्पादक सेवा के तर्क से परिचित हैं।

एक्ज़ीक्यूटर्स उपयोगिता वर्ग के अन्य तरीकों के अनुरूप , newCachedThreadPool विधि में एक अतिभारित संस्करण भी है जो थ्रेडफ़ैक्टरी ऑब्जेक्ट को एक तर्क के रूप में लेता है।