2010-10-21 20 views

उत्तर

38

ExecutorService कच्चे Thread जैसे निचले स्तर के अबास्ट्रक्शन से जुड़े कई जटिलताओं को दूर करता है। यह कार्यों की सफल या अचानक समाप्ति पर सुरक्षित रूप से शुरू करने, बंद करने, सबमिट करने, निष्पादित करने और अवरुद्ध करने के लिए तंत्र प्रदान करता है (Runnable या Callable के रूप में व्यक्त)।

JCiP से, धारा 6.2, सीधे घोड़े के मुंह से:

Executor एक सरल अंतरफलक हो सकता है, लेकिन यह है कि काम की एक विस्तृत विविधता का समर्थन करता है अतुल्यकालिक कार्य निष्पादन के लिए एक लचीला और शक्तिशाली ढांचे के लिए आधार बनाता निष्पादन नीतियां यह कार्य निष्पादन से कार्य प्रस्तुत करने decoupling, Runnable के रूप में कार्य का वर्णन करने का एक मानक साधन प्रदान करता है। Executor कार्यान्वयन आंकड़े एकत्रण, आवेदन प्रबंधन और निगरानी जोड़ने के लिए जीवन चक्र समर्थन और हुक भी प्रदान करते हैं। ... एक Executor का उपयोग आमतौर पर अपने आवेदन में एक निर्माता-उपभोक्त डिजाइन को लागू करने के लिए सबसे आसान रास्ता है।

समानांतरवाद के लिए अंतर्निहित बुनियादी ढांचे (, और महान प्रयास के साथ अक्सर गलत तरीके से) अपने समय बिताने को लागू करने के बजाय, j.u.concurrent ढांचे आप के बजाय संरचना कार्य, निर्भरता, संभावित समानांतरवाद पर ध्यान केंद्रित करने की अनुमति देता है। समवर्ती अनुप्रयोगों के बड़े पैमाने पर, कार्य सीमाओं की पहचान और शोषण करना और j.u.c का उपयोग करना सरल है, जिससे आप वास्तविक समेकन चुनौतियों के बहुत छोटे सबसेट पर ध्यान केंद्रित कर सकते हैं, जिसके लिए अधिक विशिष्ट समाधान की आवश्यकता हो सकती है।

इसके अलावा, बॉयलरप्लेट नज़र के बावजूद और लग रहा है, Oracle API page summarizing the concurrency utilities उन्हें प्रयोग करने के कुछ वास्तव में ठोस तर्क भी शामिल है, कम से कम नहीं:

डेवलपर्स पहले से ही मानक पुस्तकालय वर्गों को समझने की संभावना है, इसलिए कोई एडी-एचओसी समवर्ती घटकों के एपीआई और व्यवहार सीखने की आवश्यकता है। इसके अतिरिक्त, समवर्ती अनुप्रयोग विश्वसनीय, अच्छी तरह से परीक्षण किए गए घटकों पर बनाए जाने पर डीबग करने के लिए आसान हैं।

यह question on SO एक अच्छी किताब के बारे में पूछता है, जिसके तत्काल उत्तर जेसीआईपी है। यदि आप पहले से नहीं हैं, तो खुद को एक प्रति प्राप्त करें। प्रस्तुत किए गए समेकन के लिए व्यापक दृष्टिकोण इस प्रश्न से काफी आगे जाता है, और लंबे समय तक आपको बहुत अधिक दिल का दर्द बचाएगा।

18

एक लाभ यह है मैं देख रहा हूँ कई धागे का समय निर्धारण प्रबंध/में है। निष्पादक सेवा के साथ, आपको अपना खुद का थ्रेड मैनेजर लिखना नहीं है जिसे बग से पीड़ित किया जा सकता है। यह विशेष रूप से उपयोगी होता है यदि आपके प्रोग्राम को एक साथ कई धागे चलाने की आवश्यकता है। उदाहरण के लिए आप एक समय में दो धागे पर अमल करना चाहते हैं, आप आसानी से इसे यह पसंद कर सकते हैं:

ExecutorService exec = Executors.newFixedThreadPool(2); 

exec.execute(new Runnable() { 
    public void run() { 
    System.out.println("Hello world"); 
    } 
}); 

exec.shutdown(); 

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

एकल धागा चलाने के लिए, मुझे निष्पादक सेवा का उपयोग करने का कोई स्पष्ट लाभ नहीं दिखता है।

+0

exec.execute है ना (नई Runnable() ..? थ्रेड Runnable लागू करता है के बाद से – devnull

+0

या तो ठीक है। सरल मामलों के लिए, Runnable पर्याप्त होना चाहिए। – Manny

+1

मैं वास्तव में बनाने में किसी भी बिंदु वहाँ नहीं लगता कि एक ' थ्रेड 'जब आपको केवल' रननेबल 'की आवश्यकता होती है ... आप' थ्रेड 'भी शुरू नहीं कर रहे हैं, इसलिए यह केवल भ्रम और अनावश्यक सामान जोड़ता है। – ColinD

9

Runnable इंटरफ़ेस को कार्यान्वित करके कार्य को चलाने के लिए, हमें Thread जैसे new thread(RunnableObject).start() का ऑब्जेक्ट बनाना होगा। लेकिन हम जानते हैं कि थ्रेड बनाने का अपना ओवरहेड होता है और स्टैक और हीप मेमोरी में संग्रहीत होता है। केवल थ्रेड ऑब्जेक्ट को अलग थ्रेड में चलाने के लिए केवल थ्रेड ऑब्जेक्ट बनाना बहुत महंगा है।

Executors पैकेजमें जावा 5 द्वारा जारी फ्रेमवर्क (java.util.concurrent.Executor), थ्रेड ऑब्जेक्ट के बिना रननेबल थ्रेड ऑब्जेक्ट्स को चलाने के लिए प्रयोग किया जाता है।

"Executor ढांचा निष्पादन नीतियों के एक सेट के अनुसार अतिक्रमण कार्यों के आविष्कार, शेड्यूलिंग, निष्पादन और नियंत्रण को मानकीकृत करने के लिए एक ढांचा है।"

9

नीचे कुछ लाभ हैं:

  1. निर्वाहक सेवा अतुल्यकालिक रास्ता
  2. उपयोग प्रतिदेय धागा पूरा होने के बाद वापसी परिणाम प्राप्त करने के लिए धागा लेते हैं।
  3. स्वचालित रूप से
  4. कांटा नए काम बताए के लिए मुफ्त धागा और धागे से पुनर्विक्रय पूरा काम करने के लिए काम के आवंटन का प्रबंधन करें - समानांतर प्रसंस्करण के लिए ढांचे में शामिल होने
  5. धागे
  6. invokeAll और invokeAny किसी भी चलाने के लिए अधिक नियंत्रण दे के बीच
  7. बेहतर संचार या सभी धागा एक ही बार में
  8. बंद सभी धागा सौंपा काम
  9. अनुसूचित निर्वाहक सेवाएं runnables का दोहरा आमंत्रण के उत्पादन के लिए विधियां उपलब्ध करा पूरा करने के लिए क्षमता प्रदान करते हैं और callables आशा है कि यह होगा मदद से आप
+1

क्या यह कॉल करने योग्य के बजाय दूसरे बिंदु पर "भविष्य" नहीं है? भविष्य वह है जहां हम थ्रेड पूरा होने के बाद परिणाम/मूल्य पुनर्प्राप्त कर सकते हैं। – AmitG

+0

हां उदाहरण के लिए। भविष्य भविष्य = execorService.submit (कॉल करने योग्य); –

1

जावा से पहले 1.5 संस्करण, थ्रेड/Runnable दो अलग-अलग सेवाओं

  1. काम की यूनिट के लिए डिजाइन किया गया था
  2. काम की है कि इकाई के निष्पादन

ExecutorService उन अलग करता काम की इकाई के रूप में चलाने योग्य (लाइफसाइक्लिंग के साथ) निष्पादित करने के लिए एक तंत्र के रूप में रननेबल/कॉल करने योग्य द्वारा नामित दो सेवाएं

1

एक्जिक्यूटर्स सर्विस भी फ्यूचरटास्क तक पहुंच प्रदान करता है जो एक बार पूरा होने के बाद कॉलिंग क्लास में पृष्ठभूमि कार्य के परिणाम लौटाएगा। निर्वाहक ढांचे से दूर पारंपरिक थ्रेड से प्रतिदेय

public class TaskOne implements Callable<String> { 

@Override 
public String call() throws Exception { 
    String message = "Task One here. . ."; 
    return message; 
    } 
} 

public class TaskTwo implements Callable<String> { 

@Override 
public String call() throws Exception { 
    String message = "Task Two here . . . "; 
    return message; 
    } 
} 

// from the calling class 

ExecutorService service = Executors.newFixedThreadPool(2); 
    // set of Callable types 
    Set<Callable<String>>callables = new HashSet<Callable<String>>(); 
    // add tasks to Set 
    callables.add(new TaskOne()); 
    callables.add(new TaskTwo()); 
    // list of Future<String> types stores the result of invokeAll() 
    List<Future<String>>futures = service.invokeAll(callables); 
    // iterate through the list and print results from get(); 
    for(Future<String>future : futures) { 
     System.out.println(future.get()); 
    } 
5

निम्नलिखित सीमाओं को लागू करने के मामले में (बिल्ट-इन थ्रेड पूल ढांचा)।

  • गरीब संसाधन प्रबंधन अर्थात यह हर अनुरोध के लिए नए संसाधन बनाने पर रहते हैं। संसाधन बनाने की कोई सीमा नहीं है।निष्पादक ढांचे का उपयोग हम मौजूदा संसाधनों का पुन: उपयोग कर सकते हैं और संसाधन बनाने पर सीमा डाल सकते हैं।
  • मजबूत नहीं: यदि हम नए धागे को बनाते रहेंगे तो हमें StackOverflowException अपवाद मिलेगा जिसके परिणामस्वरूप हमारा जेवीएम क्रैश हो जाएगा।
  • समय के ओवरहेड निर्माण: प्रत्येक अनुरोध के लिए हम नए संसाधन बनाना होगा। नया संसाधन बनाने के लिए समय लेने वाला है। यानी थ्रेड बनाना> कार्य। निष्पादक ढांचे का उपयोग हम थ्रेड पूल में निर्मित कर सकते हैं। थ्रेड पूल के

लाभ

  • थ्रेड पूल का उपयोग अनुरोध या कार्य प्रसंस्करण के दौरान धागा निर्माण से परहेज द्वारा प्रतिक्रिया समय कम कर देता है। थ्रेड पूल के

  • उपयोग आप अपने निष्पादन नीति में परिवर्तन के रूप में आप की जरूरत है की अनुमति देता है। आप केवल execorService कार्यान्वयन को प्रतिस्थापित करके सिंगल थ्रेड से एकाधिक थ्रेड तक जा सकते हैं। जावा आवेदन में

  • थ्रेड पूल धागे प्रणाली लोड और उपलब्ध संसाधन के आधार पर निर्णय लिया का एक कॉन्फ़िगर किया गया नंबर बनाने के द्वारा प्रणाली की स्थिरता बढ़ जाती है।

  • थ्रेड पूल धागा प्रबंधन सामान से आवेदन डेवलपर को मुक्त कर देते और व्यापार तर्क पर ध्यान केंद्रित करने की अनुमति देता है।

Source

1

यह वास्तव में है कि एक नया धागा बनाने के लिए महंगा है?

बेंचमार्क के रूप में, मैंने Runnable एस के साथ run() विधियों के साथ 60,000 धागे बनाए हैं। प्रत्येक थ्रेड बनाने के बाद, मैंने तुरंत start(..) विधि को बुलाया। इसमें लगभग 30 सेकंड तीव्र CPU गतिविधि हुई। this question के जवाब में इसी तरह के प्रयोग किए गए हैं। उनमें से सारांश यह है कि यदि धागे तुरंत खत्म नहीं होते हैं, और बड़ी संख्या में सक्रिय धागे जमा होते हैं (कुछ हज़ार), तो समस्याएं हो सकती हैं: (1) प्रत्येक थ्रेड में ढेर होता है, इसलिए आप स्मृति से बाहर हो जाएंगे , (2) ओएस द्वारा लगाए गए प्रति प्रक्रिया धागे की संख्या पर एक सीमा हो सकती है, लेकिन not necessarily, it seems

तो, जहां तक ​​मैं देख सकता हूं, अगर हम प्रति सेकंड 10 धागे लॉन्च करने के बारे में बात कर रहे हैं, और वे सभी नए शुरू होने से तेज़ी से खत्म हो जाते हैं, और हम गारंटी दे सकते हैं कि यह दर बहुत अधिक नहीं होगी , तो निष्पादक सेवा दृश्य प्रदर्शन या स्थिरता में कोई ठोस लाभ प्रदान नहीं करती है। (हालांकि यह कोड में कुछ समवर्ती विचारों को व्यक्त करने के लिए इसे और अधिक सुविधाजनक या पठनीय बना सकता है।) दूसरी तरफ, यदि आप प्रति सेकेंड सैकड़ों या हजारों कार्य शेड्यूल कर रहे हैं, जो चलाने में समय लगता है, तो आप बड़ी समस्याओं में भाग ले सकते हैं तुरंत। यह अप्रत्याशित रूप से हो सकता है, उदा। यदि आप किसी सर्वर के अनुरोधों के जवाब में धागे बनाते हैं, और आपके सर्वर को प्राप्त अनुरोधों की तीव्रता में एक स्पाइक है। लेकिन उदा। प्रत्येक उपयोगकर्ता इनपुट इवेंट (कुंजी प्रेस, माउस गति) के जवाब में एक धागा पूरी तरह ठीक लगता है, जब तक कि कार्य संक्षिप्त होते हैं।

संबंधित मुद्दे