2009-11-06 17 views
43

कहें कि मेरे पास निम्न कोड है:निष्पादकों से RuntimeExceptions को सही ढंग से कैसे पकड़ें?

ExecutorService executor = Executors.newSingleThreadExecutor(); 
executor.execute(myRunnable); 

अब, यदि myRunnableRuntimeExcpetion फेंकता है, तो मैं इसे कैसे पकड़ सकता हूं? एक तरीका newSingleThreadExecutor() में अपना खुद का ThreadFactory कार्यान्वयन प्रदान करना होगा और Thread s के लिए कस्टम uncaughtExceptionHandler s सेट करना होगा जो इससे निकलता है। एक और तरीका myRunnable को स्थानीय (अज्ञात) Runnable में लपेटना होगा जिसमें एक कोशिश-पकड़-ब्लॉक शामिल है। शायद अन्य समान कामकाज भी हैं। लेकिन ... किसी भी तरह यह गंदे लगता है, मुझे लगता है कि यह जटिल नहीं होना चाहिए। क्या कोई साफ समाधान है?

+1

ईमानदारी से मैं एक अपवाद एक * अलग * धागा में फेंक दिया पकड़ने की भावना सवाल उठाते हैं। क्या वर्तमान धागे को थ्रेड में शामिल होना है और अपवाद को फेंकने की प्रतीक्षा है? आपने उस सवाल को कवर नहीं किया था। – BalusC

+2

@BalusC: वापस एक कॉलिंग धागा पर एक कार्यकर्ता धागे से एक अपवाद मार्शलिंग कई अनुप्रयोगों का एक आम आवश्यकता है। उदाहरण के लिए, एक यूआई आवेदन कुछ पृष्ठभूमि प्रसंस्करण करने के लिए एक SwingWorker धागा आह्वान कर सकते हैं। यदि प्रसंस्करण विफल रहता है तो अपवाद को इवेंट डिस्पैच थ्रेड पर वापस भेजना होगा। – Adamski

+2

यह एक आम आवश्यकता है। थ्रेड 1, कुछ कार्यों को उत्पन्न करती धागा 2 के माध्यम से इसे कार्यान्वित करता है, लेकिन समझने के लिए अगर यह सफल रहा है या की जरूरत नहीं है (यानी एक अपवाद फेंका)। निष्पादक ढांचा आपको इसके साथ मदद करता है। –

उत्तर

54

स्वच्छ वर्कअराउंड execute() के बजाय ExecutorService.submit() का उपयोग करना है।

ExecutorService executor = Executors.newSingleThreadExecutor(); 
Runnable task = new Runnable() { 
    public void run() { 
    throw new RuntimeException("foo"); 
    } 
}; 

Future<?> future = executor.submit(task); 
try { 
    future.get(); 
} catch (ExecutionException e) { 
    Exception rootException = e.getCause(); 
} 
+0

धन्यवाद, ठीक उसी तरह दिखता है जिस तरह से * इच्छित * होना चाहिए। स्वच्छ। –

+2

इसके अलावा, आप 'रननेबल' की बजाय 'कॉल करने योग्य' का उपयोग करना चाह सकते हैं, फिर आपका कार्य चेक अपवादों को अनचेक कर सकता है। – skaffman

+1

getCause 1.6 और 1.7 –

9

ExecutorService#submit() पर कॉल क्यों न करें, Future वापस प्राप्त करें और फिर Future#get() पर कॉल करते समय संभावित अपवादों को संभालें?

6

skaffman सही है कि submit का उपयोग कर साफ दृष्टिकोण है: यह आपको एक Future जो आप परिणाम या कार्य के अपवाद को पुनः प्राप्त करने का उपयोग कर सकते देता है। एक वैकल्पिक दृष्टिकोण ThreadPoolExecutor उपclass और afterExecute(Runnable, Throwable) ओवरराइड करना है। यदि आप इस दृष्टिकोण का पालन करते हैं execute(Runnable) को submit(Runnable) या afterExecute के बजाय कॉल करने के लिए सुनिश्चित करें।

प्रति एपीआई विवरण:

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

नोट: कार्यों (जैसे FutureTask के रूप में) कार्यों या तो स्पष्ट रूप से या विधियों के माध्यम से में बंद होते हैं जब इस तरह के रूप सबमिट करते हैं, इन कार्य पकड़ वस्तुओं और कम्प्यूटेशनल अपवादों को बनाए रखने, और तो वे अचानक समाप्ति का कारण नहीं है, और आंतरिक अपवाद इस विधि पर पास नहीं हुए हैं।

8

एक और runnable जो क्रम अपवाद पकड़ता है और उन्हें संभालती में runnable डेकोरेट:

public class REHandler implements Runnable { 
    Runnable delegate; 
    public REHandler (Runnable delegate) { 
     this.delegate = delegate; 
    } 
    public void run() { 
     try { 
      delegate.run(); 
     } catch (RuntimeException e) { 
      ... your fancy error handling here ... 
     } 
    } 
} 

executor.execute(new REHandler (myRunnable)); 
2

एक कार्य (Callable या Runnable) ThreadPoolExecutors को किए गए एक FuturnTask में कन्वर्ट हो जाएगा, नाम के एक प्रोप शामिल callable आपके द्वारा सबमिट किए गए कार्य के बराबर है। इस प्रकार FuturnTask की अपनी run विधि है। c.call() में फेंकने वाले सभी अपवाद या फेंकने वाले को outcome नामक प्रोप में रखा जाएगा।जब FuturnTask के get विधि बुला, outcome Jdk1.8 स्रोत कोड से throwed किया जाएगा

FuturnTask.run

public void run() { 
     ... 
     try { 
      Callable<V> c = callable; 
      if (c != null && state == NEW) { 
       V result; 
       boolean ran; 
       try { 
        result = c.call(); 
        ran = true; 
       } catch (Throwable ex) { 
        result = null; 
        ran = false; 
        // save ex into `outcome` prop 
        setException(ex); 
       } 
       if (ran) 
        set(result); 
      } 
     } 
     ... 
    } 

यदि आप अपवाद को पकड़ने के हैं:

      1. skaffman के जवाब
      2. अधिलेखित `afterExecute` जब आप एक ThreadPoolExecutor नई
 @Override 
     protected void afterExecute(Runnable r, Throwable t) { 
      super.afterExecute(r, t); 
      Throwable cause = null; 
      if (t == null && r instanceof Future) { 
       try { 
        ((Future<?>) r).get(); 
       } catch (InterruptedException | ExecutionException e) { 
        cause = e; 
       } 
      } else if (t != null) { 
       cause = t; 
      } 
      if (cause != null) { 
       // log error 
      } 
     } 
संबंधित मुद्दे