2012-03-01 15 views
15

मैंने चारों ओर देखा है लेकिन मुझे कोई जवाब नहीं मिला है इसलिए मैं निश्चित रूप से इसकी पुष्टि करना चाहता था।जावा थ्रेड पूल/निष्पादक सेवा और प्रतीक्षा() एस - धागे और कार्य कतार के साथ क्या होता है?

pool.execute(new Runnable(){ 
    try{ 
     Object waitForMe = doSomethingAndGetObjectToWaitFor(); 
     waitForMe.wait(); 
     doSomethingElse(); 
    }catch(Exception e){ throw new RunTimeException(e) } 

}); 

को लगता है कि इसके बाद के संस्करण कोड में कुछ 100 बार कहा जाता है की सुविधा देता है: ExecutorService pool = Executors.newFixedThreadPool(5);

और मैं कुछ कोड है -

मैं एक निश्चित आकार थ्रेड पूल है कहो। पूल में केवल 5 धागे हैं (इसलिए उपरोक्त में से केवल 5 बयान एक बिंदु पर लाइव होना चाहिए)। यह भी मान लें कि wait() किसी ऑब्जेक्ट पर कुछ I/O कॉल को एक थर्ड पार्टी में कर रहा है और ऑपरेशन पूरा होने पर कॉलबैक की प्रतीक्षा कर रहा है, इसलिए इसे स्वाभाविक रूप से पूरा करने में कुछ समय लगेगा।

अब मेरा प्रश्न यह है कि इन कार्यों में से एक wait() तक पहुंचने पर व्यवहार क्या होता है, क्या कार्य सो जाता है और फिर थ्रेड पूल से धागा कतार से एक और कार्य लेता है और इसे चलाने शुरू करता है?

यदि काम करने का कार्य सो रहा है तो क्या होता है जब यह notify() प्राप्त होता है और उठता है? क्या थ्रेड थ्रेड पूल के लिए कतार में (सामने या पीछे) वापस जाता है और तब तक प्रतीक्षा करता है जब तक कि 5 धागे में से कोई भी इसे निष्पादित नहीं कर सकता (यानी doSomethingelse() पर कॉल करें)? या जो धागा इसे निष्पादित कर रहा था वह भी सो जाता है यानी 5 निष्पादक धागे में से एक कार्य के साथ इंतजार कर रहा है (यही वह है जो मैं मान रहा हूं)? या क्या निष्पादक थ्रेड एक और कार्य उठाता है और जब पहला कार्य प्रतीक्षा() से वापस आता है तो बस बाधित हो जाता है?

उत्तर

16

wait() एक अवरुद्ध ऑपरेशन है:

जब तक एक और धागा invokes सूचित() विधि या notifyAll() प्रतीक्षा करने के लिए वर्तमान धागा कारण

इसका मतलब है कि पूल में धागा इंतजार करेंगे, लेकिन बाहर से ऐसा लगता है कि वर्तमान कार्य को पूरा करने में इतना समय लगता है। इसका यह भी अर्थ है कि यदि 5 कार्य निष्पादित किए जाते हैं और वे सभी wait(), Executor शेष कार्यों को संभाल नहीं सकते हैं, ekhem, कतार में प्रतीक्षा करें।

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

एक और दिलचस्प विशेषता में बाधा डालती है - अगर थ्रेड किसी चीज की प्रतीक्षा करता है या सो जाता है तो आप इसे बाधित कर सकते हैं। ध्यान दें कि wait() और Thread.sleep()InterruptedException दोनों घोषित करें। ExecutorService के साथ आप आसानी से कॉल करके इसका लाभ उठा सकते हैं: future.cancel() (future वह वस्तु है जो आपको ExecutorService पर कार्य सबमिट करते समय बदले में मिली है)।

अंततः मुझे लगता है कि आपको अपने समाधान को फिर से डिजाइन करना चाहिए।

pool.execute(new Runnable(){ 
    try{ 
     doSomethingAndCallMeBackWhenItsDone(new Callback() { 
      public void done() { 
       doSomethingElse(); 
      } 
     }); 
    }catch(Exception e){ throw new RunTimeException(e) } 

}); 

इस तरह बाहरी प्रणाली के एपीआई बस आपको सूचित करेंगे जब परिणाम के लिए तैयार हैं और आप प्रतीक्षा करें और ExecutorService ब्लॉक करने के लिए नहीं होगा: सक्रिय रूप से समाप्त करने के लिए एक बाहरी प्रणाली के लिए इंतजार करने के बजाय, कॉलबैक के साथ एक एपीआई प्रदान ।

pool.execute(new Runnable(){ 
    try{ 
     doSomethingAndCallMeBackWhenItIsDone(new Callback() { 
      public void done() { 
       pool.submit(new Callbale<Void>() { 
        public Void call() { 
         doSomethingElse(); 
        } 
       } 
      } 
     }); 
    }catch(Exception e){ throw new RunTimeException(e) } 

}); 

अद्यतन: अंत में, doSomethingElse() बहुत समय लेता है, तो आप भी यह शेड्यूल करने के लिए बाहरी तीसरे पक्ष के आई/ओ धागा का उपयोग कर तय कर सकते हैं और साथ ही के बजाय आप समय समाप्ति के बारे में क्या करना है पूछ रहे हैं?

pool.execute(new Runnable(){ 
    try{ 
     doSomethingAndCallMeBackWhenItsDone(new Callback() { 
      public void done() { 
       doSomethingElse(); 
      } 
      public void timeout() { 
       //opps! 
      } 
     }); 
    }catch(Exception e){ throw new RunTimeException(e) } 

}); 

मुझे लगता है कि आप तीसरे पक्ष के पक्ष में टाइमआउट लागू कर सकते हैं और यदि समय समाप्त वहाँ होता है, बस timeout() विधि कॉल: यहाँ मेरा विचार है।

+1

महान उत्तर के लिए धन्यवाद! कॉलबैक विकल्प के साथ, टाइमआउट सेट करने के बारे में जाने का सबसे अच्छा तरीका क्या होगा (अगर कोई त्रुटि नहीं फेंकती है तो कॉलबैक के लिए एक्स सेकेंड का इंतजार करना चाहते हैं)। एकमात्र तरीका मैं सोच सकता हूं कि वर्तमान सिस्टम मिलीसेक्स का नोट लेना और उसे एक सूची में रखना है और एक और धागा कॉल के लिए सूची की निगरानी करता है जो वर्तमान समय से अधिक है और एक त्रुटि ट्रिगर करता है। मुझे एक अच्छी किताब मिलनी है जो समेकन, कॉलबैक इत्यादि से संबंधित है। धन्यवाद! – NightWolf

+1

@ नाइटवॉल्फ: टाइमआउट पर wrt मेरा अद्यतन उत्तर देखें। जब एक अच्छी किताब की बात आती है, [प्रैक्टिस में जावा कंसुरेंसी] (http://www.amazon.com/Java-Concurrency- अभ्यास- ब्रायन-Goetz/dp/0321349601) एक जरूरी है। –

+0

अद्यतन और पुस्तक लिंक, अच्छा विचार के लिए धन्यवाद ढेर। अफसोस की बात है कि मेरे पास तीसरे पक्ष के पक्ष में कोई नियंत्रण नहीं है। – NightWolf

1

wait() ट्रेड पूल के बारे में कुछ भी नहीं पता। और थ्रेड पूल wait() के बारे में कुछ भी नहीं जान सकता है। तो वे किसी भी तरह से बातचीत नहीं कर सकते हैं।

वे सामान्य रूप से काम करते हैं - wait() बस एक लंबे समय से चलने वाले ब्लॉकिंग ऑपरेशन है, थ्रेड पूल थ्रेड के सीमित पूल पर चलाने के लिए रननेबल की कतार है।

0

मैं टॉमसज़ के उत्तर पर टिप्पणी करता हूं लेकिन मेरी प्रतिष्ठा इसे (अभी तक) क्षमा नहीं करती है।

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

0

सभी 5 धागे अवरुद्ध किए जाएंगे और एप्लिकेशन गैर-उत्पादक स्थिति में होगा।

को Tomasz जवाब जोड़ना, मैं इस प्रकार समय के लिए बाहर तंत्र को लागू करना चाहते हैं। TimeoutException से

  Future<Long> futureResult = service.execute(myCallable); 
      Long result = null; 
      try{ 
       result = futureResult.get(5000, TimeUnit.MILLISECONDS); 
      }catch(TimeoutException e){ 
       System.out.println("Time out after 5 seconds"); 
       futureResult.cancel(true); 
      }catch(InterruptedException ie){ 
       System.out.println("Error: Interrupted"); 
      }catch(ExecutionException ee){ 
       System.out.println("Error: Execution interrupted"); 
      } 

अलावा, आप InterruptedException & ExecutionException दौरान भविष्य रद्द कर सकते हैं। यदि आप निष्पादित करने के बजाय सबमिट() का उपयोग करते हैं(), InterruptedException & ExecutionException ढांचे में स्वयं निगल जाएगा।

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