2010-08-05 11 views
13

मैं कार्यों को शेड्यूल करने के लिए ThreadPoolExecutor का उपयोग करने का प्रयास कर रहा हूं, लेकिन इसकी नीतियों के साथ कुछ समस्याओं में चल रहा हूं। यहां बताया गया है:ThreadPoolExecutor नीति

  1. यदि कोरपूलसाइज थ्रेड से कम चल रहे हैं, तो निष्पादक हमेशा कतार के बजाए एक नया धागा जोड़ना पसंद करता है।
  2. यदि कोरपूलसाइज या अधिक थ्रेड चल रहे हैं, तो निष्पादक हमेशा एक नया धागा जोड़ने के बजाय अनुरोध को क्यूइंग करना पसंद करता है।
  3. यदि कोई अनुरोध कतारबद्ध नहीं किया जा सकता है, तो एक नया धागा तब तक बनाया जाता है जब तक कि यह अधिकतम पुलसाइज से अधिक न हो, इस स्थिति में, कार्य को खारिज कर दिया जाएगा।

व्यवहार मैं चाहता हूँ यह है:

  1. एक ही जैसा कि ऊपर
  2. तो corePoolSize की तुलना में अधिक है, लेकिन maximumPoolSize धागे से कम चल रहे हैं, पसंद करते हैं कतार में एक नया थ्रेड जोड़ने, और एक निष्क्रिय धागा का उपयोग कर एक नया धागा जोड़ने पर।
  3. ही मैं किसी भी कार्य को अस्वीकार कर दिया जा नहीं करना चाहती ऊपर

मूल रूप से के रूप में; मैं चाहता हूं कि उन्हें एक असंबद्ध कतार में कतारबद्ध किया जाए। लेकिन मैं अधिकतम पुलसाइज थ्रेड तक रखना चाहता हूं। यदि मैं एक असंबद्ध कतार का उपयोग करता हूं, तो यह CoreSize हिट करने के बाद कभी थ्रेड उत्पन्न नहीं करता है। यदि मैं एक बाध्य कतार का उपयोग करता हूं, तो यह कार्यों को अस्वीकार करता है। क्या इसके आसपास कोई रास्ता है?

अब मैं जो सोच रहा हूं वह थ्रेडपूलएक्सएटर को सिंक्रोनस क्यूयू पर चला रहा है, लेकिन सीधे कार्यों को खिला नहीं रहा - बल्कि उन्हें एक अलग असंबद्ध लिंक्डब्लॉकिंग्यूयू में खिला रहा है। फिर एक और धागा LinkedBlockingQueue से निष्पादक में फ़ीड करता है, और यदि कोई खारिज हो जाता है, तो यह तब तक फिर से प्रयास करता है जब तक इसे खारिज नहीं किया जाता है। यह दर्द और एक हैक की तरह लगता है, हालांकि - क्या ऐसा करने का एक क्लीनर तरीका है?

उत्तर

1

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

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

1

बस corePoolsize = maximumPoolSize सेट करें और एक असंबद्ध कतार का उपयोग करें?

अंक की आपकी सूची में, 1 2 को छोड़ देता है, क्योंकि corePoolSize हमेशा maximumPoolSize से कम या बराबर होगा।

संपादित

अभी भी कुछ आप क्या चाहते हैं और आप क्या TPE की पेशकश करेगा के बीच असंगत है।

यदि आपके पास एक असंबद्ध कतार है, तो maximumPoolSize को अनदेखा किया गया है, जैसा कि आपने देखा है, corePoolSize धागे कभी भी बनाए और उपयोग नहीं किए जाएंगे।

तो, यदि आप corePoolsize = maximumPoolSize को एक असंबद्ध कतार के साथ लेते हैं, तो आपके पास जो चाहिए, है ना?

+0

ओह, मैंने जो लिखा वह बिल्कुल वैसा ही नहीं था जो मैं चाहता था। मैंने मूल संपादित किया। –

+0

कोरपूलसाइज सेट करना = maxPoolSize वास्तव में करीब है, लेकिन मैं allowCoreThreadTimeOut (false) और prestartAllCoreThreads() को भी उपयोग कर रहा हूं। –

4

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

एक कैश्ड थ्रेड पूल संभावित असीमित समवर्ती धागे की अनुमति देते हुए निष्क्रिय धागे का पुन: उपयोग करेगा।यह निश्चित रूप से विस्फोट अवधि के दौरान संदर्भ स्विचिंग ओवरहेड से अपमानजनक प्रदर्शन को जन्म दे सकता है।

Executors.newCachedThreadPool(); 

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

corePoolSize = maximumPoolSize = N; 
allowCoreThreadTimeOut(true); 
setKeepAliveTime(aReasonableTimeDuration, TimeUnit.SECONDS); 

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

अंतिम विकल्प हैकिश है। मूल रूप से, ThreadPoolExecutor कतार में क्षमता निर्धारित करने के लिए आंतरिक रूप से BlockingQueue.offer का उपयोग करता है। BlockingQueue का एक कस्टम कार्यान्वयन हमेशा offer प्रयास को अस्वीकार कर सकता है। जब ThreadPoolExecutoroffer कतार में एक कार्य करने में विफल रहता है, तो यह एक नया कार्यकर्ता बनाने का प्रयास करेगा। यदि कोई नया कर्मचारी नहीं बनाया जा सकता है, तो RejectedExecutionHandler कहा जाएगा। उस बिंदु पर, एक कस्टम RejectedExecutionHandler कस्टम BlockingQueue में put को मजबूर कर सकता है।

/** Hackish BlockingQueue Implementation tightly coupled to ThreadPoolexecutor implementation details. */ 
class ThreadPoolHackyBlockingQueue<T> implements BlockingQueue<T>, RejectedExecutionHandler { 
    BlockingQueue<T> delegate; 

    public boolean offer(T item) { 
     return false; 
    } 

    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { 
     delegate.put(r); 
    } 

    //.... delegate methods 
}