2009-08-24 19 views
14

मुझे कई कार्य सबमिट करने की आवश्यकता है और फिर सभी परिणामों के उपलब्ध होने तक उनके लिए प्रतीक्षा करें। उनमें से प्रत्येक String को Vector (जो डिफ़ॉल्ट रूप से सिंक्रनाइज़ किया गया है) जोड़ता है। फिर मुझे वेक्टर में प्रत्येक परिणाम के लिए एक नया कार्य शुरू करने की आवश्यकता है, लेकिन मुझे ऐसा करने की ज़रूरत है जब पिछले सभी कार्यों ने अपना काम बंद कर दिया हो।जावा निष्पादक: कार्य समाप्ति के लिए प्रतीक्षा करें।

मैं जावा एक्जिक्यूटर का उपयोग करना चाहता हूं, विशेष रूप से मैंने थ्रेड की निश्चित संख्या का उपयोग करने के लिए Executors.newFixedThreadPool(100) का उपयोग करने की कोशिश की है (मेरे पास कार्य की एक चर संख्या है जो 10 या 500 हो सकती है) लेकिन मैं निष्पादकों के साथ नया हूं और मैं कार्य समाप्ति की प्रतीक्षा कैसे करें, यह नहीं पता। यह मेरा कार्यक्रम क्या करने की जरूरत के एक स्यूडोकोड की तरह कुछ है:

ExecutorService e = Executors.newFixedThreadPool(100); 
while(true){ 

/*do something*/ 

for(...){ 
<start task> 
} 

<wait for all task termination> 

for each String in result{ 
<start task> 
} 

<wait for all task termination> 
} 

क्योंकि मैं थोड़ी देर के (सही) में हूँ और मैं executorService पुन: उपयोग करने की जरूरत है मैं एक e.shutdown ऐसा नहीं कर सकते ..

क्या आप मेरी मदद कर सकते हैं? क्या आप मुझे जावा निष्पादकों के बारे में एक गाइड/पुस्तक सुझा सकते हैं?

+0

क्या e.submit के बीच का अंतर (मुझे लगता है कि मैं इस अपने उदाहरण का अनुसरण उपयोग करने की आवश्यकता) और ई है http://stackoverflow.com/questions/1228433/java-parallel-work-iterator/1228445 – Tim

उत्तर

21

ExecutorService आपको एक साथ कई कार्यों को निष्पादित करने के लिए एक तंत्र देता है और Future ऑब्जेक्ट्स का संग्रह प्राप्त करता है (कार्य की असीमित गणना का प्रतिनिधित्व करता है)।

Collection<Callable<?>> tasks = new LinkedList<Callable<?>>(); 
//populate tasks 
for (Future<?> f : executorService.invokeAll(tasks)) { //invokeAll() blocks until ALL tasks submitted to executor complete 
    f.get(); 
} 

आप Callable रों बजाय Runnable रों है, तो आप आसानी से विधि का उपयोग कर एक Callable<Object> में एक Runnable कर सकते हैं:

Callable<?> c = Executors.callable(runnable); 
+4

पुरानी पोस्ट खोदने के लिए खेद है, लेकिन मुझे f.get() को कॉल करने में बिंदु नहीं दिख रहा है; invokeAll() स्वयं अवरुद्ध हो रहा है, इसलिए जब तक आप परिणाम में रुचि रखते हैं (जिसे आपका कोड नहीं है) प्राप्त करने की आवश्यकता नहीं है()। – hooch

+0

@ हूच: आईएमओ आपको हमेशा 'कॉल() 'को कॉल करना चाहिए यदि आपके' कॉल करने योग्य 'ने अपवाद फेंक दिया हो। अन्यथा यह सिर्फ खो जाता है। –

2

जब आप किसी निष्पादक सेवा में सबमिट करते हैं, तो आपको Future ऑब्जेक्ट वापस मिल जाएगा।

उन वस्तुओं को संग्रह में संग्रहीत करें, और फिर बदले में get() पर कॉल करें। अंतर्निहित नौकरी पूरा होने तक get() ब्लॉक, और नतीजा यह है कि प्रत्येक अंतर्निहित नौकरियां समाप्त होने के बाद get() पर कॉल करना समाप्त हो जाएगा।

उदा

Collection<Future> futures = ... 
for (Future f : futures) { 
    Object result = f.get(); 
    // maybe do something with the result. This could be a 
    // genericised Future<T> 
} 
System.out.println("Tasks completed"); 

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

+0

पर एक नज़र डालें ।निष्पादित?? – Raffo

+0

अंतर यह है कि सबमिट करने के साथ आपको भविष्य वापस मिल जाता है और निष्पादित करने के साथ आप नहीं करते हैं। यदि आप अपने 'थ्रेड फैक्ट्री' का उपयोग 'अनकॉटएक्सप्शन हैंडलर' के साथ करते हैं, तो 'निष्पादित करें' हैंडलर को बिना किसी अपवाद के अपवाद प्राप्त होंगे, जबकि 'सबमिट' नहीं होगा - आपको केवल 'भविष्य' के माध्यम से अपवाद मिलेगा 'विधि –

14

तुम मुझे बता सकते हैं एक गाइड/पुस्तक के बारे में जावा निष्पादकों ??

मैं इस हिस्से का जवाब कर सकते हैं:

Java Concurrency in Practice ब्रायन गोएज़ (टिम Peierls, Joshua Bloch, यूसुफ Bowbeer, डेविड होम्स और Doug Lea के साथ) द्वारा सबसे अधिक संभावना है आपका सर्वश्रेष्ठ दांव है।

यह केवल निष्पादकों के बारे में हालांकि नहीं है, लेकिन बजाय सामान्य रूप में java.util.concurrent पैकेज है, साथ ही बुनियादी संगामिति अवधारणाओं और तकनीकों, और इस तरह जावा स्मृति मॉडल के रूप में कुछ उन्नत विषयों को शामिल किया गया।

+0

यह एक उत्कृष्ट पुस्तक है, हालांकि शुरुआती लोगों के लिए वास्तव में एक नहीं है। –

14

बल्कि सीधे एक Executor को Runnable या Callable रों प्रस्तुत करने और इसी Future वापसी मान मैं जब यह पूरा करता है प्रत्येक Futureपुनः प्राप्त करने के एक CompletionService कार्यान्वयन का उपयोग की सलाह देते हैं भंडारण की तुलना में। यह दृष्टिकोण कार्यों के उत्पादन को पूरा कार्यों की खपत से हटा देता है, उदाहरण के लिए नए कार्यों को समय-समय पर निर्माता धागे पर उत्पन्न करने की इजाजत देता है।

Collection<Callable<Result>> workItems = ... 
ExecutorService executor = Executors.newSingleThreadExecutor(); 
CompletionService<Result> compService = new ExecutorCompletionService<Result>(executor); 

// Add work items to Executor. 
for (Callable<Result> workItem : workItems) { 
    compService.submit(workItem); 
} 

// Consume results as they complete (this would typically occur on a different thread). 
for (int i=0; i<workItems.size(); ++i) { 
    Future<Result> fut = compService.take(); // Will block until a result is available. 
    Result result = fut.get(); // Extract result; this will not block. 
} 
+0

प्रैक्टिस में इसमें उपरोक्त मेरे उदाहरण की तुलना में अधिक LOC शामिल है। एक पूर्ण सेवा आमतौर पर उपयोगी होती है यदि आप कई स्थानों से कार्य सबमिट कर रहे हैं लेकिन कार्य पूर्णता को लगातार संभालना चाहते हैं (उदाहरण के लिए, कुछ अन्य गणना करने के लिए) - जिसे आप केवल –

+1

@oxbow परिभाषित करना चाहते हैं: या यदि आप प्रसंस्करण परिणाम प्रारंभ करना चाहते हैं जैसे ही पहला कार्य पूरा हो जाता है! अन्यथा आप अपने सबसे धीमे काम की प्रतीक्षा कर रहे हैं जबकि अन्य पहले ही कर चुके हैं .. (एडमस्की +1) – Tim

+1

@ टिम - ओपी ने स्पष्ट रूप से कहा कि वह सभी कार्यों को समाप्त होने तक इंतजार करना चाहता था, इसलिए इससे कोई फर्क नहीं पड़ता (अन्य कुछ नैनोसेकंड) जो कार्य पहले खत्म होता है। –

1
ExecutorService executor = ... 
//submit tasks 
executor.shutdown(); // previously submitted tasks are executed, 
        // but no new tasks will be accepted 
while(!executor.awaitTermination(1, TimeUnit.SECONDS)) 
    ; 

कस्टम ExecutorService बनाए बिना आप क्या चाहते हैं करने के लिए कोई आसान तरीका नहीं है।

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