2010-02-24 22 views
49

मैंने हमेशा पढ़ा है कि धागे बनाना महंगा है।
मुझे यह भी पता है कि आप धागे को फिर से नहीं चला सकते हैं।जावा थ्रेड पुन: उपयोग

मैं Executors वर्ग के दस्तावेज़ में देखें:

एक थ्रेड पूल है कि नए सूत्र रूप में की जरूरत बनाता है बनाता है, लेकिन पहले से निर्माण धागे का पुन: उपयोग होगा, जब वे उपलब्ध हैं।

शब्द 'पुन: उपयोग' करें।

थ्रेड पूल 'पुन: उपयोग' धागे कैसे करते हैं?

उत्तर

44

मुझे लगता है कि मैं समझ गया कि तुम क्या confuzzabling इसलिए यहाँ मेरी अब जवाब है: (जाहिर है, या आप विशेष रूप से 'फिर से' पर जोर देने के डाल कि सवाल पूछने नहीं होता) शब्दावली एक छोटा सा भ्रामक है:

थ्रेड पूल 'पुन: उपयोग' धागे कैसे करते हैं?

क्या हो रहा है किसी एकल थ्रेड कई कार्यों (आमतौर पर Runnable के रूप में पारित कार्रवाई करने के लिए इस्तेमाल किया जा सकता है, लेकिन यह अपने 'निष्पादक' ढांचे पर निर्भर है: डिफ़ॉल्ट निष्पादकों Runnable स्वीकार करता है, लेकिन आप अपने खुद के "निष्पादक लिख सकता है "/ थ्रेड-पूल Runnable की तुलना में कुछ अधिक जटिल स्वीकार कर रहा है [जैसे, कहें, CancellableRunnable])।

अब डिफ़ॉल्ट ExecutorService कार्यान्वयन में यदि किसी थ्रेड को अभी भी उपयोग में होने पर समाप्त किया गया है, तो इसे स्वचालित रूप से एक नए थ्रेड के साथ बदल दिया जाता है, लेकिन यह 'पुन: उपयोग' नहीं है जिसके बारे में वे बात कर रहे हैं। इस मामले में कोई "पुन: उपयोग नहीं" है।

तो यह है कि आप दो बार एक जावा थ्रेड पर start() कॉल नहीं कर सकते, लेकिन जैसा कि आप एक प्रबंधक करना चाहते हैं आप के रूप में कई Runnable पारित कर सकते हैं और प्रत्येक Runnable के run() विधि एक बार कहा जाता है किया जाएगा सच है।

आप पास कर सकते हैं 30 Runnable 5 जावा Thread और प्रत्येक कार्यकर्ता धागा कॉल कर रहे हैं, उदाहरण के लिए run() 6 बार (व्यावहारिक रूप से इसकी गारंटी नहीं दे रहा है कि आप वास्तव में 6 Runnable प्रति Thread क्रियान्वित हो जाएगा, लेकिन यह एक विस्तार है)।

इस उदाहरण में start() को 6 बार कहा जाएगा। हर एक को इन 6 start()ठीक एक बार प्रत्येक Thread की run() विधि कॉल करेगा:

Thread.start() जावाडोक से:

* Causes this thread to begin execution; the Java Virtual Machine 
* calls the <code>run</code> method of this thread. 

लेकिन तो प्रत्येक थ्रेड के run() विधि के अंदर Runnable dequeued किया जाएगा और प्रत्येक Runnable की run() विधि को बुलाया जा रहा है। तो प्रत्येक धागा कई Runnable संसाधित कर सकता है। यही वह है जिसे वे "धागा पुन: उपयोग" कहते हैं।

एक तरह से अपनी खुद की थ्रेड पूल करने के लिए जो करने के लिए आप runnables enqueue और, अपने सूत्र के प्रत्येक है एक बार यह अगले Runnable (या ब्लॉक) विपंक्ति एक Runnable की run() विधि संसाधित किया जाना पूर्ण, पर एक अवरुद्ध कतार उपयोग करने के लिए है और run() विधि चलाएं, फिर कुल्लाएं और दोहराएं।

मैं भ्रम की स्थिति का हिस्सा लगता है (और यह है एक सा भ्रामक) तथ्य यह है कि एक Thread एक Runnable और start() बुला पर Runnable के run() विधि कहा जाता है लेता है, जबकि डिफ़ॉल्ट धागा पूल भीRunnable लेने से आता है ।

+22

टीएल; डॉ थ्रेड पूल थ्रेड मूल रूप से लूप चला रहे हैं जो सबमिट किए गए कार्यों को कतार से बाहर खींचते हैं।जब वे कार्य की सेवा करते हैं तो थ्रेड निष्पादित करना बंद नहीं करते हैं, वे बस अगले को कतार में सबमिट करने की प्रतीक्षा करते हैं। प्रश्न में पूछे गए अनुसार वे कभी भी 'पुनर्मिलन' नहीं करते हैं, क्योंकि वे लगातार चल रहे हैं। – Sogger

4

थ्रेड पूल में कई निश्चित कार्यकर्ता थ्रेड होते हैं जो आंतरिक कार्य कतार से कार्य ले सकते हैं। तो यदि एक कार्य समाप्त होता है, तो धागा अंत नहीं करता है लेकिन अगले कार्य की प्रतीक्षा करता है। यदि आप धागे को रोकते हैं, तो यह स्वचालित रूप से बदल जाता है।

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

-4

यदि thread समाप्त हो गया है, तो सुनिश्चित करें कि कोई इसे दोबारा उपयोग कर सकता है। आप यह सुनिश्चित कर सकते हैं कि यह isAlive() या कुछ समान कॉल करके नहीं चल रहा है।

संपादित करें: अगर किसी ने thread निलंबित कर दिया है, तो कोई भी फिर से शुरू नहीं कर सकता है। मुझे नहीं लगता कि यह सामान्य रूप से समाप्त होने पर क्यों शुरू नहीं किया जा सकता है। लेकिन मैं संदेह का लाभ देता हूं और कहता हूं इसे पुन: उपयोग नहीं किया जा सकता है।

+4

@fastcodejava: यदि कोई थ्रेड समाप्त हो गया है तो आप * प्रारंभ() * को फिर से कॉल नहीं कर सकते हैं, जो आपको * * अवैध थ्रेडस्टेट अपवाद * प्रदान करेगा। – SyntaxT3rr0r

12

run थ्रेड पूल में धागे की विधि में केवल एक ही कार्य नहीं होता है। थ्रेड पूल में run धागे की विधि में लूप होता है। यह एक कतार के कार्य को खींचता है, कार्य निष्पादित करता है (जो लौटता है पूर्ण होने पर), और फिर अगला कार्य प्राप्त करता है। run विधि तब तक पूर्ण नहीं होती है जब तक थ्रेड की आवश्यकता नहीं होती है। जोड़ने के लिए

संपादित:

यहाँ ThreadPoolExecutor में Worker भीतरी वर्ग के run तरीका है।

696:   /** 
697:   * Main run loop 
698:   */ 
699:   public void run() { 
700:    try { 
701:     Runnable task = firstTask; 
702:     firstTask = null; 
703:     while (task != null || (task = getTask()) != null) { 
704:      runTask(task); 
705:      task = null; // unnecessary but can help GC 
706:     } 
707:    } finally { 
708:     workerDone(this); 
709:    } 
710:   } 
+0

@ माइक डेनियल: बिल्कुल ... उसने कहा, आपको उस सन कोड से प्यार करना होगा जो * "task = null;" * असाइन करता है और फिर टिप्पणी करता है * "// अनावश्यक लेकिन जीसी की मदद कर सकता है" *। आप यहां कोड का एक टुकड़ा पोस्ट कर रहे हैं और ऐसा करने के लिए आप समूह के गलतियों से अपने गले पर कूदेंगे, यह बताएंगे कि यह कितना व्यर्थ है;) – SyntaxT3rr0r

+5

@ जादूगर: यह वास्तव में अनावश्यक नहीं है - कार्य के लिए (अजीब) परीक्षण! = लूप में नल लगातार एक ही कार्य को संसाधित करने के लिए आवश्यक बनाता है। यहां तक ​​कि यदि लूप अधिक पारंपरिक नलिंग कार्य अच्छा होगा, अन्यथा अगर GetTask() लंबे समय तक ब्लॉक करता है, तो कार्य की जीसी अन्यथा उसी अवधि के लिए देरी होगी। –

+0

@ सॉफ्टवेयर बंदर: दूसरे बिंदु के बारे में बहुत अंतर्दृष्टि। 'GetTask' शायद एक टाइमआउट के साथ एक अवरुद्ध कतार से बाहर खींच रहा है। यह टाइमआउट की पूरी लंबाई के लिए अवरुद्ध हो सकता है। यदि कार्य में बहुत से फ़ील्ड हैं (कार्य में पास पैरामीटर के लिए), पहले जीसी सहायक होगा। –

0

एक थ्रेड पूल अपने धागे बनाता है और उन धागे के लिए अपने स्वयं के चालाक छोटे Runnables प्रदान करता है। उन रननेबल्स कभी खत्म नहीं होते हैं लेकिन कतार में सिंक्रनाइज़ करते हैं (वे प्रतीक्षा करते हैं()) जब तक कि उस कतार में एक कॉलबल मौजूद न हो; जब ऐसा होता है तो उन्हें अधिसूचित किया जाता है और उनका रननेबल कतार से कॉल करने योग्य चलाता है और पूरा परिदृश्य खुद को दोहराता है।

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