2009-02-11 8 views
37

सबसे पहले, मुझे यह कहना होगा कि मैं एपीआई java.util.concurrent के लिए काफी नया हूं, इसलिए शायद मैं जो कर रहा हूं वह पूरी तरह से गलत है।क्या यह java.util.concurrent.FutureTask का उपयोग करने का एक अच्छा तरीका है?

मैं क्या करना चाहता हूं?

मैं एक जावा अनुप्रयोग है कि मूल रूप से 2 अलग प्रसंस्करण (myFirstProcess, mySecondProcess कहा जाता है) चलाता है, लेकिन इन प्रसंस्करण एक साथ चलाए किया जाना चाहिए।

तो, मैं ऐसा करने की कोशिश की:

public void startMyApplication() { 
    ExecutorService executor = Executors.newFixedThreadPool(2); 
    FutureTask<Object> futureOne = new FutureTask<Object>(myFirstProcess); 
    FutureTask<Object> futureTwo = new FutureTask<Object>(mySecondProcess); 
    executor.execute(futureOne); 
    executor.execute(futureTwo); 
    while (!(futureOne.isDone() && futureTwo.isDone())) { 
     try { 
      // I wait until both processes are finished. 
      Thread.sleep(1000); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
    logger.info("Processing finished"); 
    executor.shutdown(); 
    // Do some processing on results 
    ... 
} 

myFirstProcess और mySecondProcess कक्षाएं कि Callable<Object> लागू करता है, और जहां उनके सभी प्रसंस्करण कॉल() विधि में किया जाता है।

यह काफी अच्छी तरह से काम कर रहा है लेकिन मुझे यकीन नहीं है कि ऐसा करने का यह सही तरीका है। क्या मैं चाहता हूं कि एक अच्छा तरीका है? यदि नहीं, तो क्या आप मुझे अपना कोड बढ़ाने के लिए कुछ संकेत दे सकते हैं (और अभी भी इसे यथासंभव सरल रखें)।

+3

आपकी जबकि स्थिति में एक करीबी ब्रैकेट गुम है :) –

उत्तर

43

आप get() विधि का उपयोग करके बेहतर हो जाएंगे।

futureOne.get(); 
futureTwo.get(); 

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

बोनस के रूप में, आपके पास एपीआई get(long timeout, TimeUnit unit) है जो आपको थ्रेड के लिए अधिकतम समय निर्धारित करने और प्रतिक्रिया के लिए प्रतीक्षा करने की अनुमति देता है, और अन्यथा चल रहा है।

अधिक जानकारी के लिए Java API देखें।

+0

तो कॉल करने योग्य के बजाय उसे भविष्य को लागू करना चाहिए या क्या उसे दोनों को लागू करना चाहिए? –

+1

ओह क्षमा करें, मैं आपके लिंक से उलझन में था। फ्यूचरटास्क में .get() विधि है। –

+1

एक पूर्ण सेवा सेवा का उपयोग करने के बारे में बात करने वाला उत्तर इस से कहीं बेहतर है। –

5

यदि आप एक ही समय में धागे शुरू करने में रुचि रखते हैं, या उन्हें समाप्त करने की प्रतीक्षा कर रहे हैं और फिर कुछ और प्रक्रिया कर रहे हैं, तो आप CyclicBarrier का उपयोग करना चाह सकते हैं। अधिक जानकारी के लिए javadoc देखें।

+0

मुझे यकीन नहीं है कि मुझे साइक्लिकबैरियर की विशिष्टताओं का उपयोग करने की आवश्यकता होगी, लेकिन यह एक बहुत ही रोचक वर्ग है ... – romaintaz

17

युवाल का समाधान ठीक है। एक विकल्प के रूप में आप यह भी कर सकते हैं:

ExecutorService executor = Executors.newFixedThreadPool(); 
FutureTask<Object> futureOne = new FutureTask<Object>(myFirstProcess); 
FutureTask<Object> futureTwo = new FutureTask<Object>(mySecondProcess); 
executor.execute(futureOne); 
executor.execute(futureTwo); 
executor.shutdown(); 
try { 
    executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); 
} catch (InterruptedException e) { 
    // interrupted 
} 

इस दृष्टिकोण का क्या फायदा है? वास्तव में बहुत अंतर नहीं है कि इस तरह आप निष्पादक को किसी और कार्य को स्वीकार करने से रोकते हैं (आप इसे अन्य तरीके से भी कर सकते हैं)। हालांकि मैं उस मूर्खता को उस व्यक्ति को पसंद करता हूं।

इसके अलावा, अगर कोई अपवाद फेंकता है तो आप अपने कोड के एक हिस्से में समाप्त हो सकते हैं जो मानता है कि दोनों कार्य किए जाते हैं, जो खराब हो सकता है।

+0

"अगर कोई मिलता है() अपवाद फेंकता है तो आप अपने कोड के एक हिस्से में समाप्त हो सकते हैं जो दोनों मानता है कार्य किया जाता है "निश्चित रूप से केवल तभी होता है जब आप अपवाद को निगल लें? – artbristol

+0

हां, awaitTermination का उपयोग थ्रेड.sleep() –

+0

newFixedThreadPool() से सुविधाजनक है; पैरामीटर के बिना विधि मौजूद नहीं है – Kachna

18

उपरोक्त FutureTask के उपयोग सहनशील हैं, लेकिन निश्चित रूप से मूर्ख नहीं हैं। आप वास्तव में पर सबमिट किए गए एक के आसपास अतिरिक्तFutureTask लपेट रहे हैं। FutureTask को ExecutorService द्वारा Runnable के रूप में माना जाता है। आंतरिक रूप से, यह आपके FutureTask -as- Runnable को नए FutureTask में लपेटता है और इसे Future<?> के रूप में आपके पास लौटाता है।

इसके बजाय, आपको Callable<Object> उदाहरण CompletionService पर सबमिट करना चाहिए। आप एस submit(Callable<V>) के माध्यम से दो बार ड्रॉप करते हैं, फिर चारों ओर मुड़ें और CompletionService#take() दो बार कॉल करें (एक बार प्रत्येक सबमिट Callable के लिए)। वे कॉल एक तक अवरुद्ध हो जाएंगे और फिर अन्य सबमिट किए गए कार्य पूर्ण हो जाएंगे।

यह देखते हुए कि आपके पास पहले से ही Executor है, इसके आस-पास एक नया ExecutorCompletionService बनाएं और अपने कार्यों को वहां छोड़ दें। स्पिन और सोने की प्रतीक्षा मत करो; CompletionService#take() तब तक अवरुद्ध हो जाएगा जब तक कि आपके किसी एक कार्य को पूरा नहीं किया जाता है (या तो समाप्त हो रहा है या रद्द हो गया है) या take() पर प्रतीक्षा थ्रेड बाधित है।

7

आप invokeall (Colelction ....) विधि

package concurrent.threadPool; 

import java.util.Arrays; 
import java.util.List; 
import java.util.concurrent.Callable; 
import java.util.concurrent.ExecutionException; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.Future; 

public class InvokeAll { 

    public static void main(String[] args) throws Exception { 
     ExecutorService service = Executors.newFixedThreadPool(5); 
     List<Future<java.lang.String>> futureList = service.invokeAll(Arrays.asList(new Task1<String>(),new Task2<String>())); 

     System.out.println(futureList.get(1).get()); 
     System.out.println(futureList.get(0).get()); 
    } 

    private static class Task1<String> implements Callable<String>{ 

     @Override 
     public String call() throws Exception { 
      Thread.sleep(1000 * 10); 
      return (String) "1000 * 5"; 
     } 

    } 

    private static class Task2<String> implements Callable<String>{ 

     @Override 
     public String call() throws Exception { 
      Thread.sleep(1000 * 2); 
      int i=3; 
      if(i==3) 
       throw new RuntimeException("Its Wrong"); 
      return (String) "1000 * 2"; 
     } 

    } 
} 
2

उपयोग कर सकते हैं अपने futureTasks अधिक तो 2 कर रहे हैं, [ListenableFuture][1] पर विचार करें।

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

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