2011-12-15 13 views
9

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

मुद्दा यह है कि धागा पूल पहले सेट किए जाने पर थ्रेड में सेट हो जाता है और थ्रेड पूल वास्तव में चल रहा है कि कार्य से बंधे नहीं है। मैं इसे समझता हूं ... मेरे रननेबल्स और कॉलबेल - हालांकि उनके नाम हैं - वास्तव में ThreadPoolExecutor के चल रहे थ्रेड से नीचे का एक स्तर है।

ThreadPoolExecutor थ्रेड पूल के नाम बनाने के बारे में स्टैक ओवरव्लो पर कुछ अन्य प्रश्न हैं। (How to give name to a callable Thread? और How to name the threads of a thread pool in Java देखें।)

मैं क्या जानना चाहता हूं: क्या किसी के पास थ्रेड पूल थ्रेड के नाम को रननेबल के साथ समन्वयित करने के लिए एक अच्छा समाधान है जो वास्तव में चल रहा है?

अर्थात अगर मैं Thread.getCurrentThread().getName() फोन मैं इसे नहीं थ्रेड पूल उच्च-स्तरीय के नाम वापस आना चाहते, बल्कि प्रतिदेय/Runnable का नाम है कि धागा अभी चल रहा है।

चूंकि यह मुख्य रूप से डिबगिंग और लॉगिंग उद्देश्यों के लिए है, इसलिए मैं ऐसे समाधान से बचने की कोशिश कर रहा हूं जिसमें मुझे प्रत्येक रननेबल में नया कोड डालने की कोशिश की जा रही है जो थ्रेडपूल एक्स्सेलर को सबमिट किया जा सकता है - मैंने बस कुछ कोड डाला ThreadFactory या ThreadPoolExecutor को स्वयं लपेटें ताकि परिवर्तन एक ही स्थान पर किया जा सके। यदि ऐसा समाधान मौजूद नहीं है तो शायद मैं परेशान नहीं होगा क्योंकि यह मिशन महत्वपूर्ण नहीं है।

संपादित शुरू स्पष्ट करने के लिए, मुझे पता है मैं हर Runnable के रन विधि की पहली पंक्ति के रूप में एक Thread.currentThread().setName("my runnable name"); रख सकते हैं, लेकिन मुझे लगता है कि ऐसा करने से बचने के लिए कोशिश कर रहा हूँ। मैं यहां एक पूर्णतावादी हूं, और मुझे इसका एहसास है, इसलिए अगर लोग इस प्रश्न पर टिप्पणी करना चाहते हैं और मुझे ऐसा बताना चाहते हैं तो मुझे नाराज नहीं होगा। अंत संपादित

मेरे अन्य सवाल है, मुझे लगता है, कि क्या लोगों को लगता है यह एक बुरा विचार ऐसा करने के लिए है। क्या मुझे इस तरह के थ्रेड पूल नाम को अपडेट करने से सावधान रहना चाहिए?

किसी भी सुझाव के लिए धन्यवाद!

+0

"Runnable के साथ सिंक में थ्रेड पूल धागे के नाम रखते हुए कि यह वास्तव में चल रहा है" -> Runnable/प्रतिदेय नाम निर्धारित नहीं है, इसलिए मैं काफी अपने प्रश्न का जोर नहीं देख सकते । क्या आपका थ्रेड फैक्ट्री वास्तव में प्रत्येक थ्रेड को एक अलग नाम देता है? – serg10

+0

ठीक है, मेरे प्रत्येक रननेबल्स और कॉलबल्स नामांकित इंटरफ़ेस को लागू करते हैं, इसलिए मेरे पास नामों तक पहुंच है। मुझे एहसास है कि मैं चुनौतीपूर्ण हूं कि मैंने अपने सभी रननेबल्स के लिए पहले से ही एक विशेष सुविधा लागू की है, लेकिन अतिरिक्त कोड जोड़ने से बचना चाहते हैं जो मैन्युअल रूप से थ्रेड नाम सेट करता है। –

+1

स्पष्टता के लिए संपादित, कुछ "थ्रेड पूल" को "थ्रेड" में बदलना, और कुछ "थ्रेड" को "कार्य" में बदलना। –

उत्तर

13

एक थ्रेडपूलएक्ससेलर बनाएं जो पहले एक्सेक्यूट विधि को ओवरराइड करता है।

private final ThreadPoolExecutor executor = new ThreadPoolExecutor (new ThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()){ 
    protected void beforeExecute(Thread t, Runnable r) { 
     t.setName(deriveRunnableName(r)); 
    } 

    protected void afterExecute(Runnable r, Throwable t) { 
     Thread.currentThread().setName(""); 
    } 

    protected <V> RunnableFuture<V> newTaskFor(final Runnable runnable, V v) { 
     return new FutureTask<V>(runnable, v) { 
      public String toString() { 
       return runnable.toString(); 
      } 
     }; 
    }; 
} 
नहीं

यकीन है कि कैसे वास्तव में derveRunnableName() काम करेगा, शायद toString()?

संपादित करें: थ्रेड.currentThread() वास्तव में थ्रेड पहले से सेट किया गया है जो बाद में निष्पादित करता है। आप Thread.currentThread() का संदर्भ दे सकते हैं और उसके बाद नाम को बाद में सेट कर सकते हैं।यह javadocs

/** 
* Method invoked upon completion of execution of the given Runnable. 
* This method is invoked by the thread that executed the task. If 
* non-null, the Throwable is the uncaught <tt>RuntimeException</tt> 
* or <tt>Error</tt> that caused execution to terminate abruptly. 
* 
* <p><b>Note:</b> When actions are enclosed in tasks (such as 
* {@link FutureTask}) either explicitly or via methods such as 
* <tt>submit</tt>, these task objects catch and maintain 
* computational exceptions, and so they do not cause abrupt 
* termination, and the internal exceptions are <em>not</em> 
* passed to this method. 
* 
* <p>This implementation does nothing, but may be customized in 
* subclasses. Note: To properly nest multiple overridings, subclasses 
* should generally invoke <tt>super.afterExecute</tt> at the 
* beginning of this method. 
* 
* @param r the runnable that has completed. 
* @param t the exception that caused termination, or null if 
* execution completed normally. 
*/ 
protected void afterExecute(Runnable r, Throwable t) { } 

संपादित में विख्यात है TPE एक FutureTask भीतर Runnable लपेटो जाएगा, ताकि toString विधि आप newTaskFor ओवरराइड और अपने खुद के लिपटे FutureTask बना सकते हैं समर्थन करने के लिए।

+0

मैं वास्तव में इस तरह कुछ ऐसा करने की कोशिश कर रहा हूं, तो अच्छा सुझाव। एकमात्र मुद्दा तब होता है जब रननेबल पूर्ण हो जाता है, थ्रेड पूल में अभी भी वह नाम है। दुर्भाग्यवश ओवरसीड विधि के बाद ओवरड्यूट विधि को थ्रेड नहीं मिलता है जिसमें रननेबल चलाया जाता है। जब भी मैं कर रहा हूं, मैं इसे साफ़ करने में सक्षम होना चाहता हूं। –

+1

@JeffGoldberg बाद में, Thread.currentThread() एकमात्र धागा है जिसे मैं पहले से नाम में स्थापित कर रहा हूं। मैं इसे प्रदर्शित करने के लिए अपना जवाब अपडेट करूंगा। –

+0

बहुत बढ़िया यह बहुत अच्छा है। धन्यवाद! –

2

मेरे सुझाव

pool.execute(new Runnable() { 
    public void run() { 
     Thread.getCurrentThread().setName("My descriptive Runnable"); 
     // do my descriptive Runnable 
    } 
});     

तुम भी नाम रीसेट कर सकते हैं जब आप समाप्त कर दिया है अगर आप की तरह की कोशिश करने का होगा।

+0

क्या आप सुझाव दे रहे हैं कि जब भी मैं पूल करने के लिए कॉल करता हूं। निष्पादन करता हूं या मैं पूल की निष्पादन विधि को ओवरराइड करता हूं? –

+0

मान लीजिए कि आप उस धागे को क्या दर्शा रहे हैं, इसे प्रतिबिंबित करने के लिए नाम बदलना चाहते हैं। नोट: जब रनवेबल शुरू होता है तो यह बदलेगा, न कि जब आप कॉल करते हैं। ;) –

4

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

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

जॉन विंट पता चलता है, मैं beforeExecution विधि ओवरराइड करने के लिए और उसके बाद साफ करने के लिए afterExecution विधि ओवरराइड पसंद करते हैं, लेकिन afterExecution थ्रेड में कोई संभाल नहीं है।

public class RunnableNameThreadPoolExecutor extends ThreadPoolExecutor { 

    /* Constructors... */ 

    @Override 
    public void execute(Runnable command) { 
     super.execute(new ManageNameRunnable(command)); 
    } 

    private class ManageNameRunnable implements Runnable { 
     private final Runnable command; 
     ManageNameRunnable(Runnable command) { 
      this.command = command; 
     } 

     public void run() { 
      String originalName = Thread.currentThread().getName(); 
      try { 
       String runnableName = getRunnableName(command); 
       Thread.currentThread().setName(originalName+ ": " + runnableName); 
       command.run(); 
      } finally { 
       Thread.currentThread().setName(originalName); 
      } 
     } 
    } 
} 
+1

क्या आपके पास और अधिक काम कोड है? जैसे getRunnableName() परिभाषा और नमूना कॉलिंग कोड? – peterboston

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