2010-01-20 9 views
34

मैं जावा प्रोजेक्ट पर काम कर रहा हूं जहां मुझे असीमित रूप से चलने वाले कई कार्य करने की आवश्यकता है। मुझे विश्वास है कि निष्पादक मेरे लिए ऐसा करने का सबसे अच्छा तरीका है, इसलिए मैं इसे अपने साथ परिचित कर रहा हूं। (यद्यपि सीखने के लिए भुगतान हो रहा है!) हालांकि, यह मुझे स्पष्ट नहीं है कि मैं जो करने की कोशिश कर रहा हूं उसे पूरा करने का सबसे अच्छा तरीका क्या है।जावा एक्जिक्यूटर कार्य के लिए सर्वोत्तम अभ्यास जो हमेशा के लिए चलाना चाहिए

तर्क के लिए, मान लें कि मेरे पास दो कार्य चल रहे हैं। न तो समाप्त होने की उम्मीद है, और दोनों को आवेदन के जीवन की अवधि के लिए चलना चाहिए। मैं एक मुख्य रैपर वर्ग लिखने की कोशिश कर रहा हूं कि:

  • यदि कोई कार्य अपवाद फेंकता है, तो रैपर इसे पकड़ लेगा और कार्य को पुनरारंभ करेगा।
  • यदि कोई कार्य पूरा होने के लिए चलता है, तो रैपर कार्य को नोटिस और पुनरारंभ करेगा।

अब, यह ध्यान दिया जाना चाहिए कि दोनों कार्यों के लिए कार्यान्वयन कोड run() में अनंत लूप कि पूरा करने के लिए चलाए कभी नहीं होगा, एक आज़माएं/कैच ब्लॉक कि भंग किए बिना सभी क्रम अपवाद संभाल चाहिए के साथ रैप होगा पाश। मैं निश्चितता की एक और परत जोड़ने की कोशिश कर रहा हूँ; अगर मैं या मेरे पीछे आने वाला कोई ऐसा व्यक्ति बेवकूफ़ है जो इन सुरक्षा उपायों को हरा देता है और कार्य को रोकता है, तो आवेदन को उचित प्रतिक्रिया देने की आवश्यकता होती है।

क्या इस समस्या का सामना करने के लिए सबसे अच्छा अभ्यास है कि मेरे द्वारा अधिक अनुभवी लोगों की सिफारिश की जाएगी?

Fwiw, मैं मार पड़ी-अप किया है इस परीक्षण वर्ग:


public class ExecTest { 

    private static ExecutorService executor = null; 
    private static Future results1 = null; 
    private static Future results2 = null; 

    public static void main(String[] args) { 
     executor = Executors.newFixedThreadPool(2); 
     while(true) { 
     try { 
      checkTasks(); 
      Thread.sleep(1000); 
     } 
     catch (Exception e) { 
      System.err.println("Caught exception: " + e.getMessage()); 
     } 
     } 
    } 

    private static void checkTasks() throws Exception{ 
     if (results1 == null || results1.isDone() || results1.isCancelled()) { 
     results1 = executor.submit(new Test1()); 
     } 

     if (results2 == null || results2.isDone() || results2.isCancelled()) { 
     results2 = executor.submit(new Test2()); 
     } 
    } 
} 

class Test1 implements Runnable { 
    public void run() { 
     while(true) { 
     System.out.println("I'm test class 1"); 
     try {Thread.sleep(1000);} catch (Exception e) {} 
     } 

    } 
} 

class Test2 implements Runnable { 
    public void run() { 
     while(true) { 
     System.out.println("I'm test class 2"); 
     try {Thread.sleep(1000);} catch (Exception e) {} 
     } 
    } 
} 

यह रास्ता मैं चाहता हूँ से व्यवहार कर रहा है, लेकिन मैं अगर वहाँ किसी भी gotchas हैं पता नहीं है, अक्षमताओं, या पूरी तरह गलत-headedness प्रतीक्षा मुझे आश्चर्यचकित करने के लिए। (वास्तव में, यह देखते हुए कि मैं इसके लिए नया हूं, अगर इसके बारे में कुछ गलत/अव्यवस्थित नहीं था तो मुझे आश्चर्य होगा।)

किसी भी अंतर्दृष्टि का स्वागत है।

+0

आप उन दो कार्यों यह अपने आप ही एकल पिरोया निष्पादक से प्रत्येक चलाते हैं, तो आप सिर्फ काम के 1000 प्रतियां निष्पादक में डाल सकते हैं। :-) –

+0

तो यदि कोई कार्य विफल रहता है, तो 99 9 अपनी जगह लेने का इंतजार कर रहे हैं? हे। प्यारा, लेकिन मेरा विश्वास करो, मुझे वास्तव में इस चूसने वाले को बुलेटप्रूफ होने की आवश्यकता है क्योंकि मैं इसे बना सकता हूं। इसलिए अनिवार्य रूप से एक समुदाय कोड समीक्षा के लिए यह अनुरोध। – BlairHippo

+2

ठीक है, बुलेटप्रूफ के विषय पर: डेडलॉक या अन्य लाइफ विफलताओं में आने वाले कार्यों से निपटने के लिए आपकी वर्तमान योजना क्या है? सिर्फ इसलिए कि आप बार-बार फिर से शुरू कर सकते हैं इसका मतलब यह नहीं है कि यह चल रहा रहेगा, अगर वे समस्याएं अनिश्चित काल तक उन्हें पकड़ सकती हैं। –

उत्तर

30

मैं अपने पिछले परियोजना में एक ऐसी ही स्थिति का सामना करना पड़ा है, और के बाद मेरे कोड गुस्से में ग्राहक का सामना करने में विस्फोट से उड़ा दिया, मेरे साथी और मैं दो बड़े सुरक्षित गार्ड कहा:

  1. अनंत लूप, पकड़ में त्रुटियां भी, अपवाद नहीं। कभी-कभी अप्रत्याशित चीजें होती हैं और जावा आपके ऊपर एक त्रुटि फेंकता है, अपवाद नहीं।
  2. बैक-ऑफ स्विच का उपयोग करें, इसलिए यदि कुछ गलत हो जाता है और पुनर्प्राप्त करने योग्य नहीं होता है, तो आप उत्सुकतापूर्वक एक और लूप शुरू करके स्थिति को आगे बढ़ाते नहीं हैं।इसके बजाए, आपको तब तक इंतजार करना होगा जब तक कि स्थिति सामान्य न हो जाए और फिर फिर से शुरू करें।

उदाहरण के लिए, हमारे पास एक ऐसी स्थिति थी जहां डेटाबेस नीचे चला गया और लूप के दौरान एक एसक्यूलेक्सप्शन फेंक दिया गया था। दुर्भाग्यपूर्ण परिणाम यह था कि कोड लूप के माध्यम से फिर से चला गया, केवल उसी अपवाद को फिर से मारने के लिए, और आगे। लॉग से पता चला है कि हमने एक ही SQLException को एक सेकंड में लगभग 300 बार मारा !! ... यह 5 सेकंड या उससे अधिक के मौलिक जेवीएम विराम के साथ कई बार हुआ, जिसके दौरान आवेदन उत्तरदायी नहीं था, अंत में एक त्रुटि फेंक दी गई और धागा की मृत्यु हो गई!

इसलिए हमने नीचे दिए गए कोड में दिखाए गए बैक-ऑफ रणनीति को लागू किया है, यदि अपवाद पुनर्प्राप्त करने योग्य नहीं है (या मिनटों के भीतर पुनर्प्राप्त करने के अलावा छोड़ दिया गया है), तो हम परिचालन शुरू करने से पहले लंबे समय तक प्रतीक्षा करते हैं ।

class Test1 implements Runnable { 
    public void run() { 
    boolean backoff = false; 
    while(true) { 
     if (backoff) { 
     Thread.sleep (TIME_FOR_LONGER_BREAK); 
     backoff = false; 
     } 
     System.out.println("I'm test class 1"); 
     try { 
     // do important stuff here, use database and other critical resources 
     } 
     catch (SqlException se) { 
     // code to delay the next loop 
     backoff = true; 
     } 
     catch (Exception e) { 
     } 
     catch (Throwable t) { 
     } 
    } 
    } 
} 

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

+1

दोनों सुरक्षा उपायों के लिए धन्यवाद, मैं उन्हें दोनों को ध्यान में रखूंगा। बैक-ऑफ स्विच विशेष रूप से समझदार है; मैं इसे निम्नतम स्तर के रूप में मान रहा हूं, अगर-सब कुछ-सुरक्षा में विफल रहता है। ऐसी स्थितियों के बारे में समझदार होने की कोशिश करना जो विफलता के कारण कहीं और जाएंगे; यह आसान है "कुछ बंद हो गया? ग्याह! मंगो इसे वापस चालू करें !!!" तर्क। – BlairHippo

7

इसे नजरअंदाज करने के अलावा, मैं आमतौर पर गहन मुद्दों की तलाश के लिए PMD और FindBugs जैसे स्थिर विश्लेषण टूल के खिलाफ जावा कोड चलाता हूं।

विशेष रूप से इस कोड के लिए FindBugs को यह परिणाम पसंद नहीं आया 1 और परिणाम 2 आलसी init में अस्थिर नहीं हैं, और रन() विधियां अपवाद को अनदेखा कर सकती हैं क्योंकि उन्हें स्पष्ट रूप से संभाला नहीं जा रहा है।

आम तौर पर मैं समवर्ती परीक्षण के लिए Thread.sleep के उपयोग की थोड़ी सी चीज हूं, टाइमर पसंद करता हूं या राज्य/शर्तों को समाप्त करता हूं। कॉल करने योग्य एक व्यवधान की स्थिति में कुछ लौटने में उपयोगी हो सकता है जो परिणाम की गणना करने में असमर्थ होने पर अपवाद फेंकता है।

कुछ सर्वोत्तम प्रथाओं और विचार के लिए अधिक भोजन के लिए, Concurrency in Practice देखें।

+1

युक्तियों के लिए धन्यवाद, खासकर पीएमडी और FindBugs; मैं उन उपकरणों से परिचित नहीं था। मैं अब हूँ। :-) – BlairHippo

0

क्या आपने Quartz framework को आजमाया है?

+0

नहीं, लेकिन उस पृष्ठ पर एक त्वरित नज़र डालने पर, क्वार्ट्ज ओवरकिल की तरह दिखता है। मुझे बस दो (शायद तीन) कार्यों को चलाने की ज़रूरत है और सुनिश्चित करें कि वे वास्तव में हमेशा चल रहे हैं। क्वार्ट्ज ने मुझे क्या फायदे दिए हैं कि एक आसान समाधान की कमी है? – BlairHippo

+0

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

0

कैसे के बारे में इस

Runnable task =() -> { 
    try{ 
    // do the task steps here 
    } catch (Exception e){ 
    Thread.sleep (TIME_FOR_LONGER_BREAK); 
    }  
}; 
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); 
executor.scheduleAtFixedRate(task,0, 0,TimeUnit.SECONDS); 
संबंधित मुद्दे