एक्ज़ीक्यूटर्स क्लास का newFixedThreadPool मेथड थ्रेड्स की निश्चित संख्या के साथ एक एक्ज़ीक्यूटर सर्विस बनाता है । NewSingleThreadExecutor मेथड के विपरीत , हम निर्दिष्ट करते हैं कि हमें पूल में कितने थ्रेड चाहिए। हुड के तहत, निम्नलिखित कोड कहा जाता है:


new ThreadPoolExecutor(nThreads, nThreads,
                                      	0L, TimeUnit.MILLISECONDS,
                                      	new LinkedBlockingQueue());

CorePoolSize ( निष्पादक सेवा शुरू होने पर तैयार (शुरू) होने वाले थ्रेड्स की संख्या ) और maxPoolSize ( निष्पादक सेवा द्वारा बनाए जा सकने वाले थ्रेड्स की अधिकतम संख्या ) पैरामीटर समान मान प्राप्त करते हैं - नए फ़िक्स्डथ्रेडपूल (nThreads) को दिए गए थ्रेड्स की संख्या ) . और हम उसी तरह से थ्रेडफैक्ट्री के अपने कार्यान्वयन को पारित कर सकते हैं ।

ठीक है, देखते हैं कि हमें इस तरह के ExecutorService की आवश्यकता क्यों है ।

यहाँ थ्रेड्स की एक निश्चित संख्या (n) के साथ ExecutorService का तर्क दिया गया है :

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

उदाहरण के तौर पर, हवाईअड्डे पर सुरक्षा से गुजरने की प्रतीक्षा करने की कल्पना करें। सुरक्षा जांच से ठीक पहले सभी एक पंक्ति में खड़े होते हैं, यात्रियों को सभी कामकाजी चौकियों के बीच वितरित किया जाता है। यदि किसी एक चेकपॉइंट पर देरी होती है, तो कतार को केवल दूसरे चेकपॉइंट द्वारा संसाधित किया जाएगा, जब तक कि पहला खाली न हो जाए। और यदि एक चौकी पूरी तरह से बंद हो जाती है, तो उसकी जगह पर एक और चौकी खोली जाएगी, और यात्रियों को दो चौकियों के माध्यम से संसाधित किया जाता रहेगा।

हम तुरंत ध्यान देंगे कि भले ही स्थितियाँ आदर्श हों - वादा किए गए n थ्रेड्स स्थिर रूप से काम करते हैं, और थ्रेड्स जो एक त्रुटि के साथ समाप्त होते हैं, उन्हें हमेशा बदल दिया जाता है (कुछ ऐसा जो सीमित संसाधनों को एक वास्तविक हवाई अड्डे में प्राप्त करना असंभव बना देता है) - सिस्टम में अभी भी कई हैं अप्रिय विशेषताएं, क्योंकि किसी भी परिस्थिति में अधिक धागे नहीं होंगे, भले ही कतार तेजी से बढ़ती हो, धागे कार्यों को संसाधित कर सकते हैं।

मेरा सुझाव है कि एक निश्चित संख्या में थ्रेड्स के साथ ExecutorService कैसे काम करता है, इसकी व्यावहारिक समझ प्राप्त करें । चलिए एक ऐसा वर्ग बनाते हैं जो Runnable को लागू करता है । इस वर्ग की वस्तुएँ निष्पादक सेवा के लिए हमारे कार्यों का प्रतिनिधित्व करती हैं ।


public class Task implements Runnable {
    int taskNumber;
 
    public Task(int taskNumber) {
        this.taskNumber = taskNumber;
    }
 
    @Override
    public void run() {
try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Processed user request #" + taskNumber + " on thread " + Thread.currentThread().getName());
    }
}
    

रन () विधि में , हम थ्रेड को 2 सेकंड के लिए ब्लॉक करते हैं, कुछ कार्यभार का अनुकरण करते हैं, और फिर वर्तमान कार्य की संख्या और कार्य को निष्पादित करने वाले थ्रेड का नाम प्रदर्शित करते हैं।


ExecutorService executorService = Executors.newFixedThreadPool(3);
 
        for (int i = 0; i < 30; i++) {
            executorService.execute(new Task(i));
        }
        
        executorService.shutdown();
    

आरंभ करने के लिए, मुख्य विधि में, हम एक निष्पादक सेवा बनाते हैं और निष्पादन के लिए 30 कार्य प्रस्तुत करते हैं।

संसाधित उपयोगकर्ता अनुरोध #1 पूल-1-थ्रेड-2 थ्रेड पर
संसाधित उपयोगकर्ता अनुरोध #0 पूल-1-थ्रेड-1 थ्रेड पर
संसाधित उपयोगकर्ता अनुरोध #2 पूल-1-थ्रेड-3 थ्रेड पर
संसाधित उपयोगकर्ता अनुरोध #5 पूल पर- 1-थ्रेड-3 थ्रेड
पूल-1-थ्रेड-2 थ्रेड पर संसाधित उपयोगकर्ता अनुरोध #3
पूल-1-थ्रेड-1 थ्रेड पर संसाधित उपयोगकर्ता अनुरोध #4 पूल-1-थ्रेड-1 थ्रेड
पर संसाधित उपयोगकर्ता अनुरोध #8 पूल-1-थ्रेड-1 थ्रेड
संसाधित उपयोगकर्ता अनुरोध #6 पूल-1-थ्रेड-3 थ्रेड
पर संसाधित उपयोगकर्ता अनुरोध #7 पूल-1-थ्रेड-2 थ्रेड पर
संसाधित उपयोगकर्ता अनुरोध #10 पूल-1-थ्रेड-3 थ्रेड पर
संसाधित उपयोगकर्ता अनुरोध #9 पूल-1- पर थ्रेड-1 थ्रेड
संसाधित उपयोगकर्ता अनुरोध #11 पूल-1-थ्रेड-2 थ्रेड
पर संसाधित उपयोगकर्ता अनुरोध #12 पूल-1-थ्रेड-3 थ्रेड पर
संसाधित उपयोगकर्ता अनुरोध #14 पूल-1-थ्रेड-2 थ्रेड
पर संसाधित उपयोगकर्ता अनुरोध #13 पूल-1-थ्रेड-1 थ्रेड पर
संसाधित उपयोगकर्ता अनुरोध #15 पूल-1-थ्रेड-3 थ्रेड पर
संसाधित उपयोगकर्ता अनुरोध #16 पूल पर- 1-थ्रेड-2 थ्रेड
संसाधित उपयोगकर्ता अनुरोध #17 पूल-1-थ्रेड-1 थ्रेड
संसाधित उपयोगकर्ता अनुरोध #18 पूल-1-थ्रेड-3 थ्रेड
संसाधित उपयोगकर्ता अनुरोध #19 पूल-1-थ्रेड-2 थ्रेड
संसाधित उपयोगकर्ता पर अनुरोध #20 पूल-1-थ्रेड-1 थ्रेड
पर संसाधित उपयोगकर्ता अनुरोध #21 पूल-1-थ्रेड-3 थ्रेड
पर संसाधित उपयोगकर्ता अनुरोध #22 पूल-1-थ्रेड-2 थ्रेड
संसाधित उपयोगकर्ता अनुरोध #23 पूल-1- पर थ्रेड-1 थ्रेड
संसाधित उपयोगकर्ता अनुरोध #25 पूल-1-थ्रेड-2 थ्रेड
संसाधित उपयोगकर्ता अनुरोध #24 पूल-1-थ्रेड-3 थ्रेड पर
संसाधित उपयोगकर्ता अनुरोध #26 पूल-1-थ्रेड-1 थ्रेड
पर संसाधित उपयोगकर्ता अनुरोध #27 पूल-1-थ्रेड-2 थ्रेड पर
संसाधित उपयोगकर्ता अनुरोध #28 पूल-1-थ्रेड-3 थ्रेड पर
संसाधित उपयोगकर्ता अनुरोध #29 पूल पर- 1-धागा-1 धागा

कंसोल आउटपुट हमें दिखाता है कि पिछले कार्य द्वारा जारी किए जाने के बाद कार्यों को विभिन्न थ्रेड्स पर कैसे निष्पादित किया जाता है।

अब हम कार्यों की संख्या बढ़ाकर 100 कर देंगे, और 100 कार्य सबमिट करने के बाद, हम वेट टर्मिनेशन (11, SECONDS) विधि को कॉल करेंगे। हम एक संख्या और समय इकाई को तर्क के रूप में पास करते हैं। यह विधि मुख्य थ्रेड को 11 सेकंड के लिए ब्लॉक कर देगी। तब हम सभी कार्यों के पूरा होने की प्रतीक्षा किए बिना ExecutorService को बंद करने के लिए शटडाउननाउ () कॉल करेंगे।


ExecutorService executorService = Executors.newFixedThreadPool(3);
 
        for (int i = 0; i < 100; i++) {
            executorService.execute(new Task(i));
        }
 
        executorService.awaitTermination(11, SECONDS);
 
        executorService.shutdownNow();
        System.out.println(executorService);
    

अंत में, हम निष्पादक सेवा की स्थिति के बारे में जानकारी प्रदर्शित करेंगे ।

यहाँ कंसोल आउटपुट हमें मिलता है:

संसाधित उपयोगकर्ता अनुरोध #0 पूल-1-थ्रेड-1 थ्रेड
पर संसाधित उपयोगकर्ता अनुरोध #2 पूल-1-थ्रेड-3 थ्रेड पर
संसाधित उपयोगकर्ता अनुरोध #1 पूल-1-थ्रेड-2 थ्रेड पर
संसाधित उपयोगकर्ता अनुरोध #4 पूल पर- 1-थ्रेड-3 थ्रेड
संसाधित उपयोगकर्ता अनुरोध #5 पूल-1-थ्रेड-2 थ्रेड
पर संसाधित उपयोगकर्ता अनुरोध #3 पूल-1-थ्रेड-1 थ्रेड
संसाधित उपयोगकर्ता अनुरोध #6 पूल-1-थ्रेड-3 थ्रेड
संसाधित उपयोगकर्ता पर अनुरोध #7 पूल-1-थ्रेड-2 थ्रेड
पर संसाधित उपयोगकर्ता अनुरोध #8 पूल-1-थ्रेड-1 थ्रेड पर
संसाधित उपयोगकर्ता अनुरोध #9 पूल-1-थ्रेड-3 थ्रेड
संसाधित उपयोगकर्ता अनुरोध #11 पूल-1- पर थ्रेड-1 थ्रेड
संसाधित उपयोगकर्ता अनुरोध #10 पूल-1-थ्रेड-2 थ्रेड
पर संसाधित उपयोगकर्ता अनुरोध #13 पूल-1-थ्रेड-1 थ्रेड पर
संसाधित उपयोगकर्ता अनुरोध #14 पूल-1-थ्रेड-2 थ्रेड पर
संसाधित उपयोगकर्ता अनुरोध #12 पूल-1-थ्रेड-3 थ्रेड
java.util.concurrent.ThreadPoolExecutor@452b3a41 [शट डाउन, पूल आकार = 3, सक्रिय थ्रेड्स = 3 , कतारबद्ध कार्य = 0, पूर्ण कार्य = 15]
संसाधित उपयोगकर्ता अनुरोध #17 पूल-1-थ्रेड-3 थ्रेड पर
संसाधित उपयोगकर्ता अनुरोध #15 पूल-1-थ्रेड-1 थ्रेड पर
संसाधित उपयोगकर्ता अनुरोध #16 पूल-1-थ्रेड पर -2 धागा

इसके बाद 3 इंटरप्टेड एक्सेप्शन हैं , जो 3 सक्रिय कार्यों से स्लीप मेथड्स द्वारा फेंके गए हैं।

हम देख सकते हैं कि जब कार्यक्रम समाप्त होता है, तो 15 कार्य पूरे हो जाते हैं, लेकिन पूल में अभी भी 3 सक्रिय धागे होते हैं जो अपने कार्यों को पूरा नहीं करते हैं। इन तीनों धागों पर इंटरप्ट () विधि को कॉल किया जाता है, जिसका अर्थ है कि कार्य पूरा हो जाएगा, लेकिन हमारे मामले में, स्लीप विधि एक इंटरप्टेड अपवाद को फेंक देती है । हम यह भी देखते हैं कि शटडाउन नाउ () पद्धति को कॉल करने के बाद, कार्य कतार साफ़ हो जाती है।

इसलिए पूल में एक निश्चित संख्या में थ्रेड्स के साथ ExecutorService का उपयोग करते समय , यह याद रखना सुनिश्चित करें कि यह कैसे काम करता है। यह प्रकार ज्ञात स्थिर भार वाले कार्यों के लिए उपयुक्त है।

यहाँ एक और दिलचस्प सवाल है: यदि आपको एक थ्रेड के लिए एक निष्पादक का उपयोग करने की आवश्यकता है, तो आपको किस विधि को कॉल करना चाहिए? newSingleThreadExecutor() या newFixedThreadPool(1) ?

दोनों निष्पादकों का समान व्यवहार होगा। फर्क सिर्फ इतना है कि newSingleThreadExecutor() विधि एक निष्पादक को वापस कर देगी जिसे बाद में अतिरिक्त थ्रेड्स का उपयोग करने के लिए पुन: कॉन्फ़िगर नहीं किया जा सकता है।