2015-03-26 6 views
16

मैं समझने की कोशिश कर रहा हूं कि जावा फिक्स्ड थ्रेडपूल अभ्यास में कैसे काम करता है, लेकिन दस्तावेज़ मेरे प्रश्न का उत्तर नहीं देते हैं।जावा फिक्स्ड थ्रेडपूल को समझना

की तरह एक साधारण परिदृश्य मान लें:

ExecutorService ES= Executors.newFixedThreadPool(3); 
List<Future> FL; 
for(int i=1;i<=200;i++){ 
    FL.add(ES.submit(new Task())); 
} 
ES.shutdown(); 

जहां Task एक Callable जो कुछ संसाधनों का निर्माण होता है, उनका इस्तेमाल करता है, और कुछ उत्पादन देता है।

मेरा प्रश्न: कितने Taskfor पाश पूर्ण करने पर स्मृति में देखते हैं? दूसरे शब्दों में: क्या उनके संसाधनों का निर्माण करने के समय केवल 3 Task होगा, या उनमें से सभी पहले से बनाए गए हैं, जैसे .submit मेरे पास 200 Task (और उनके संसाधन) निष्पादित करने की प्रतीक्षा कर रहे हैं?

नोट: संसाधनों निर्माण Task के निर्माता में होता है, call() विधि में नहीं।

जावाडोक (छोड़ के लिए निम्न के लिए स्वतंत्र महसूस) में: क्या मुझे confuses जावा डॉक्स

में निम्नलिखित विवरण एक धागा पूल कि धागे एक बंद ऑपरेटिंग की एक निश्चित संख्या पुनः उपयोग कर लेता बनाता है साझा unbounded कतार। किसी भी समय, अधिकांश nThreads धागे सक्रिय प्रोसेसिंग कार्य होंगे।

मुझे लगता है कि इसका मतलब है कि, मेरे उदाहरण में, सभी 200 कार्य कतार में हैं, लेकिन उनमें से केवल 3 को किसी भी समय निष्पादित किया जाता है।

किसी भी मदद की अत्यधिक सराहना की जाती है।

+0

आप लूप के ठीक बाद हैं, पूल के कतार में 'कार्य' के 200 बनाए गए उदाहरण हैं, जो एक ही समय में 3 कार्य निष्पादित करता है। – alex2410

+0

आपके प्रश्न का उत्तर नहीं दिया जा सकता है, क्योंकि यह अत्यधिक निर्भर करता है कि कब और कब कचरा कलेक्टर पूरा कार्य एकत्र करने के लिए किक करता है। – SpaceTrucker

+0

fyi 'newFixedThreadPool (nThreads) 'नए थ्रेडपूल एक्स्सेलर (एन थ्रेड, एन थ्रेड्स, 0 एल, टाइमयूनिट। मिलिस्सेन्ड्स, नई लिंक्डब्लॉकिंग क्यूयू ()) के लिए सिर्फ दृढ़ता विधि है;' – for3st

उत्तर

3

सभी 200 कार्य बनाए गए हैं और संसाधनों का उपभोग करते हैं, और वे सभी कतार में हैं।

थ्रेड पूल, केवल एक रन एक()/कॉल() विधि को एक-एक करके आमंत्रित करता है, जब निष्पादन के लिए एक मुक्त थ्रेड उपलब्ध होता है।

10

आपका कोड

for (int i = 1; i <= 200; i++){ 
    Task t = new Task(); 
    FL.add(ES.submit(t)); 
} 

के बराबर है और पाश के लिए के बाद, कार्य के निर्माता इस प्रकार 200 गुना बुलाया गया है, और कोड इसमें इस प्रकार 200 गुना मार डाला गया है। चाहे कार्य निष्पादक को सबमिट किया गया हो या नहीं, अप्रासंगिक है: आप एक लूप में 200 बार एक कन्स्ट्रक्टर का आह्वान कर रहे हैं, और के बाद प्रत्येक कार्य का निर्माण किया गया है, यह निष्पादक को सबमिट किया गया है। निष्पादक कार्यकर्ता को कॉल करने वाला नहीं है।

+0

तो, अगर मैं सही ढंग से समझता हूं, तो मेरे पास स्मृति में सभी 200 कार्य हैं।वास्तव में समानांतर में क्या किया जाता है कार्य के 'कॉल() 'विधि (जिसे' कॉल करने योग्य 'है) का निष्पादन होता है। इसलिए, मेरे पास 'कॉल()' विधि (और ऑब्जेक्ट्स और संसाधन जो बनाता है) के 3 समांतर उदाहरण होंगे। क्या मैं सही रास्ते पर हूं? – ZzKr

+1

पूल में 3 थ्रेड वास्तव में एक साथ चलते हैं, और सबमिट किए गए कार्यों की 'कॉल() 'विधि को कॉल करते हैं। हालाँकि तत्काल नहीं हैं, इसलिए कह रहे हैं कि आपके पास "कॉल() 'विधि' के 3 उदाहरण गलत हैं। –

+0

'/ उदाहरण/आमंत्रण /' –

6

कार्यों को कतार से एक करके हटा दिया जाएगा, इसलिए निष्पादन आगे बढ़ेगा, कार्य हटा दिए जाएंगे, और केवल उनका परिणाम उन भविष्य वस्तुओं में संग्रहीत किया जाएगा।

तो स्मृति में मूल रूप से

:

3 धागे
200 -> 0 टास्क
0 -> 200 भविष्य
(हर निष्पादित कार्यों के साथ)

4

आप new Task() और उन का उपयोग कर 200 वस्तुओं का निर्माण कर रहे कार्य निष्पादक को जमा कर रहे हैं। निष्पादक इस Task ऑब्जेक्ट का संदर्भ रखते हैं। तो, यदि Task के निर्माता में आप संसाधनों का निर्माण और होल्डिंग कर रहे हैं तो सभी 200 कार्य संसाधन धारण करेंगे।

यदि संभव हो, तो आप Task के कॉल विधि में संसाधन का निर्माण और उपयोग कर सकते हैं यदि आप 200 उदाहरणों को संसाधनों का निर्माण और धारण नहीं करना चाहते हैं। उस स्थिति में, एक समय में केवल 3 Task संसाधन का निर्माण और रखरखाव करेगा।

3

इसे समझने के लिए, आपको यह देखने की आवश्यकता होगी कि जब आप एक लूप में निष्पादक को कार्य सबमिट कर रहे हों तो क्या हो रहा है। सबसे पहले हम केवल निष्पादक को एक ही कार्य जमा करने पर विचार करेंगे। मैं अब JDK 1.7.0_51 स्रोत कोड

स्थिर विधि Executor.newFixedThreadPool विधि एक ThreadPoolExecutor रिटर्न एक अवरुद्ध कतार युक्त कार्य

public static ExecutorService newFixedThreadPool(int nThreads) { 
     return new ThreadPoolExecutor(nThreads, nThreads, 
             0L, TimeUnit.MILLISECONDS, 
             new LinkedBlockingQueue<Runnable>()); 
    } 

पल आप इस निर्वाहक के लिए एक कार्य जोड़ने के धारण करने के लिए की चर्चा करते हुए किया जाएगा, इस पर चला जाता है ThreadPoolExecutor की सबमिट विधि AbstractExecutorService विस्तारित करती है जहां सबमिट विधि का कार्यान्वयन लिखा जाता है।

public <T> Future<T> submit(Callable<T> task) { 
     if (task == null) throw new NullPointerException(); 
     RunnableFuture<T> ftask = newTaskFor(task); 
     execute(ftask); 
     return ftask; 
    } 

निष्पादित विधि कार्यान्वयन विशिष्ट (निर्वाहक के विभिन्न प्रकार इसे लागू अलग अलग तरीकों से जिसका अर्थ है)

अब असली मांस आता है। यह निष्पादन विधि ThreadPoolExecutor में परिभाषित है। विशेष रूप से टिप्पणियों पर ध्यान देना। यहां थ्रेडपूलएक्ससेटर के corePoolSize जैसे कुछ कॉन्फ़िगरेशन पैरामीटर खेल में आते हैं।

public void execute(Runnable command) { 
     if (command == null) 
      throw new NullPointerException(); 
     /* 
     * Proceed in 3 steps: 
     * 
     * 1. If fewer than corePoolSize threads are running, try to 
     * start a new thread with the given command as its first 
     * task. The call to addWorker atomically checks runState and 
     * workerCount, and so prevents false alarms that would add 
     * threads when it shouldn't, by returning false. 
     * 
     * 2. If a task can be successfully queued, then we still need 
     * to double-check whether we should have added a thread 
     * (because existing ones died since last checking) or that 
     * the pool shut down since entry into this method. So we 
     * recheck state and if necessary roll back the enqueuing if 
     * stopped, or start a new thread if there are none. 
     * 
     * 3. If we cannot queue task, then we try to add a new 
     * thread. If it fails, we know we are shut down or saturated 
     * and so reject the task. 
     */ 
     int c = ctl.get(); 
     if (workerCountOf(c) < corePoolSize) { 
      if (addWorker(command, true)) 
       return; 
      c = ctl.get(); 
     } 
     if (isRunning(c) && workQueue.offer(command)) { 
      int recheck = ctl.get(); 
      if (! isRunning(recheck) && remove(command)) 
       reject(command); 
      else if (workerCountOf(recheck) == 0) 
       addWorker(null, false); 
     } 
     else if (!addWorker(command, false)) 
      reject(command); 
    } 
संबंधित मुद्दे