एक्झिक्युटर्स क्लासची नवीन फिक्स्ड थ्रेडपूल पद्धत ठराविक थ्रेड्ससह एक एक्झिक्यूटर सर्व्हिस तयार करते . newSingleThreadExecutor पद्धतीच्या विपरीत , आम्ही पूलमध्ये किती थ्रेड्स हवे ते निर्दिष्ट करतो. हुड अंतर्गत, खालील कोड म्हणतात:


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

corePoolSize ( एक्झिक्युटर सेवा सुरू झाल्यावर तयार होणार्‍या (सुरू होणार्‍या थ्रेड्सची संख्या ) आणि MaxPoolSize ( एक्झिक्युटर सेवा तयार करू शकणार्‍या थ्रेड्सची कमाल संख्या ) पॅरामीटर्स समान मूल्य प्राप्त करतात — नवीन फिक्स्ड थ्रेडपूल (nThreads) ला पास केलेल्या थ्रेडची संख्या ) . आणि आम्ही थ्रेडफॅक्टरी ची स्वतःची अंमलबजावणी अगदी त्याच प्रकारे पास करू शकतो.

बरं, आम्हाला अशा ExecutorService ची गरज का आहे ते पाहू या .

थ्रेड्सची निश्चित संख्या (n) असलेल्या ExecutorService चे तर्क येथे आहे :

  • प्रक्रियेच्या कार्यासाठी जास्तीत जास्त n थ्रेड सक्रिय असतील.
  • n पेक्षा जास्त कार्ये सबमिट केल्यास, थ्रेड्स मुक्त होईपर्यंत त्यांना रांगेत धरले जाईल.
  • थ्रेडपैकी एक अयशस्वी झाल्यास आणि संपुष्टात आल्यास, त्याची जागा घेण्यासाठी एक नवीन धागा तयार केला जाईल.
  • पूल बंद होईपर्यंत पूलमधील कोणताही धागा सक्रिय असतो.

उदाहरण म्हणून, विमानतळावर सुरक्षेतून जाण्यासाठी वाट पाहण्याची कल्पना करा. सुरक्षा तपासणीच्या ताबडतोब आधी प्रत्येकजण एका ओळीत उभा राहतो, प्रवाशांना सर्व कार्यरत चेकपॉइंट्समध्ये वितरीत केले जाते. एका चेकपॉईंटवर उशीर झाल्यास, पहिला चेकपॉईंट मोकळा होईपर्यंत रांगेवर फक्त दुसर्‍यानेच प्रक्रिया केली जाईल. आणि जर एक चेकपॉईंट पूर्णपणे बंद झाला, तर त्याच्या जागी दुसरा चेकपॉईंट उघडला जाईल आणि दोन चेकपॉईंटद्वारे प्रवाशांवर प्रक्रिया केली जाईल.

आम्ही लगेच लक्षात ठेवू की परिस्थिती आदर्श असली तरीही — वचन दिलेले n थ्रेड स्थिरपणे कार्य करतात आणि त्रुटीसह समाप्त होणारे थ्रेड नेहमी बदलले जातात (जे मर्यादित संसाधनांमुळे वास्तविक विमानतळावर साध्य करणे अशक्य होते) — सिस्टममध्ये अजूनही अनेक आहेत अप्रिय वैशिष्ट्ये, कारण कोणत्याही परिस्थितीत जास्त थ्रेड्स नसतील, जरी रांग थ्रेड्स कार्यांवर प्रक्रिया करू शकतील त्यापेक्षा वेगाने वाढली तरीही.

ExecutorService ठराविक थ्रेड्ससह कसे कार्य करते याबद्दल व्यावहारिक समज मिळवण्याचा सल्ला मी देतो . Runnable ची अंमलबजावणी करणारा वर्ग तयार करू . या वर्गातील ऑब्जेक्ट्स ExecutorService साठी आमच्या कार्यांचे प्रतिनिधित्व करतात .


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-थ्रेड-2 थ्रेडवर प्रक्रिया केलेली वापरकर्ता विनंती
#1 पूल-1-थ्रेड
-1 थ्रेडवर प्रक्रिया केलेल्या वापरकर्त्याची विनंती
#0 1-थ्रेड-3 थ्रेड
पूल-1-थ्रेड-2 थ्रेडवर प्रक्रिया केलेली वापरकर्ता विनंती #3
पूल-1-थ्रेड-1 थ्रेडवर प्रक्रिया केलेली वापरकर्ता विनंती #4 पूल-1
-थ्रेड-1 थ्रेडवर प्रक्रिया केलेली वापरकर्ता विनंती #8
प्रक्रिया केलेला वापरकर्ता पूल-1-थ्रेड-3 थ्रेडवर विनंती #6
प्रक्रिया केलेली वापरकर्ता विनंती #7 पूल-1-थ्रेड-2 थ्रेडवर
प्रक्रिया केलेली वापरकर्ता विनंती #10 पूल-1-थ्रेड-3 थ्रेडवर
प्रक्रिया केलेली वापरकर्ता विनंती #9 पूल-1- वर थ्रेड-1 थ्रेड
पूल-1-थ्रेड-2 थ्रेडवर प्रक्रिया केलेली वापरकर्ता विनंती #11
पूल-1-थ्रेड-3 थ्रेडवर प्रक्रिया केलेली वापरकर्ता विनंती #12
पूल-1-थ्रेड-2 थ्रेडवर प्रक्रिया केलेली वापरकर्ता विनंती #14 पूल
-1-थ्रेड-1 थ्रेडवर
प्रक्रिया केलेली वापरकर्ता विनंती #13 पूल-1-थ्रेड-3 थ्रेडवर प्रक्रिया केलेली वापरकर्ता विनंती #15
पूल- वर प्रक्रिया केलेली वापरकर्ता विनंती #16 1-थ्रेड-2 थ्रेड
पूल-1-थ्रेड-1 थ्रेडवर
प्रक्रिया केलेली वापरकर्ता विनंती #
17
पूल-1-थ्रेड-1 थ्रेडवर
विनंती #20 प्रक्रिया केलेली वापरकर्ता विनंती #21 पूल-1-थ्रेड-3 थ्रेडवर
प्रक्रिया केलेली वापरकर्ता विनंती #22 पूल-1-थ्रेड-2 थ्रेडवर
प्रक्रिया केलेली वापरकर्ता विनंती #23 पूल-1- वर थ्रेड-1 थ्रेड
पूल-1-थ्रेड-2 थ्रेडवर प्रक्रिया केलेली वापरकर्ता विनंती #25
पूल-1-थ्रेड-3 थ्रेडवर प्रक्रिया केलेली वापरकर्ता विनंती #24
पूल-1-थ्रेड-1 थ्रेडवर
प्रक्रिया केलेली वापरकर्ता विनंती #
26
1-थ्रेड-1 धागा

कन्सोल आऊटपुट आम्हाला दाखवते की मागील टास्क द्वारे रिलीझ झाल्यानंतर वेगवेगळ्या थ्रेड्सवर कार्ये कशी कार्यान्वित केली जातात.

आता आम्ही टास्कची संख्या 100 पर्यंत वाढवू आणि 100 टास्क सबमिट केल्यानंतर, आम्ही awaitTermination(11, SECONDS) पद्धतीला कॉल करू. आम्ही वितर्क म्हणून संख्या आणि वेळ एकक पास करतो. ही पद्धत 11 सेकंदांसाठी मुख्य धागा अवरोधित करेल. मग आम्ही सर्व टास्क पूर्ण होण्याची प्रतीक्षा न करता ExecutorService ला सक्तीने बंद करण्यासाठी shutdownNow() कॉल करू .


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);
    

शेवटी, आम्ही executorService च्या स्थितीबद्दल माहिती प्रदर्शित करू .

आम्हाला मिळालेले कन्सोल आउटपुट येथे आहे:


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

यानंतर 3 व्यत्ययित अपवाद आहेत , 3 सक्रिय कार्यांमधून झोपेच्या पद्धतींद्वारे फेकले जातात.

आम्ही पाहू शकतो की प्रोग्राम संपल्यावर, 15 कार्ये पूर्ण केली जातात, परंतु पूलमध्ये अद्याप 3 सक्रिय थ्रेड होते ज्यांनी त्यांची कार्ये पूर्ण केली नाहीत. या तीन थ्रेड्सवर interrupt () पद्धत कॉल केली जाते, याचा अर्थ कार्य पूर्ण होईल, परंतु आमच्या बाबतीत, स्लीप पद्धत एक InterruptedException टाकते . आपण हे देखील पाहतो की shutdownNow() पद्धत कॉल केल्यानंतर, कार्य रांग साफ केली जाते.

त्यामुळे पूलमध्ये ठराविक थ्रेड्ससह ExecutorService वापरताना , ते कसे कार्य करते हे लक्षात ठेवा. हा प्रकार ज्ञात स्थिर भार असलेल्या कार्यांसाठी योग्य आहे.

येथे आणखी एक मनोरंजक प्रश्न आहे: जर तुम्हाला एकाच थ्रेडसाठी एक्झिक्युटर वापरण्याची आवश्यकता असेल, तर तुम्ही कोणत्या पद्धतीला कॉल करावा? newSingleThreadExecutor() किंवा newFixedThreadPool(1) ?

दोन्ही निष्पादकांना समान वर्तन असेल. फरक एवढाच आहे की newSingleThreadExecutor() पद्धत एक एक्झिक्यूटर देईल ज्याला नंतर अतिरिक्त थ्रेड्स वापरण्यासाठी पुन्हा कॉन्फिगर केले जाऊ शकत नाही.