2010-07-05 10 views
5

मैं एक तरीका है जिसके धारणात्मक, तरह दिखता है लिखने के लिए कैसे: अलग के साथ,interruptable तरीकों

Object longProcess1(Object o1) { 
    Object o2 = longSubProcess1(o1); 
    return longSubProcess2(o2); 
} 

बहुत आगे है और:

Object f(Object o1) { 
    Object o2 = longProcess1(o1); 
    Object o3 = longProcess2(o2); 
    return longProcess3(o3); 
} 

कहाँ प्रक्रियाओं खुद भी यौगिक हो सकता है विभिन्न मॉड्यूल में संभावित रूप से बैठे प्रक्रियाओं। अधिकांश प्रक्रियाएं लंबी हैं क्योंकि वे कम्प्यूटेशनल रूप से महंगा हैं, आईओ-बाउंड नहीं।

अब तक इतना अच्छा है, लेकिन अब मैं पूरी तरह से f को बाधित करने के लिए चाहता हूं। The recommended Java way to do that समय-समय पर बाधित फ्लैग को Thread.interrupted() के साथ जांचना है। यह बहुत सरल है, लेकिन यह जल्दी से बोझिल हो सकता है अगर मैं की तरह कुछ करने के लिए अपने तरीकों को बदलने की जरूरत:

Object f(Object o1) { 
    Object o2 = longProcess1(o1); 
    if (Thread.interrupted()) throw new InterruptedException(); 
    Object o3 = longProcess2(o2); 
    if (Thread.interrupted()) throw new InterruptedException(); 
    return longProcess3(o3); 
} 

Object longProcess1(Object o1) { 
    Object o2 = longSubProcess1(o1); 
    if (Thread.interrupted()) throw new InterruptedException(); 
    return longSubProcess2(o2); 
} 

... 

अब, मुझे लगता है कि की तरह काम करने के लिए समझते हैं तर्कसंगत - यह मुझे बेहतर नियंत्रण के लिए अनुमति देता है जब InterruptedException (उदाहरण के लिए) फेंक दिया जाएगा, असंगत राज्यों में वस्तुओं को छोड़ने से परहेज - लेकिन मुझे यह जानकर उत्सुकता है कि * करने का एक और शानदार तरीका है या नहीं।

* जावा में, AspectJ नहीं, जो मुझे लगता है कि यहां बहुत उपयुक्त है लेकिन मैं जावा के साथ फंस गया हूं।

+0

मैं कोड है कि धागे कि एक दूसरे रेफरी शामिल साथ गतिरोध के बारे में चिंतित होगा। –

उत्तर

7

आप एक अंतरफलक और एक गतिशील प्रॉक्सी इस्तेमाल कर सकते हैं:

public class Wrapper { 
    public static <T> T wrap(Class<T> intf, final T impl) { 
     ClassLoader cl = Thread.currentThread().getContextClassLoader(); 
     Object proxy = Proxy.newProxyInstance(cl, new Class<?>[] {intf}, 
       new InvocationHandler() { 
      public Object invoke(Object proxy, Method method, Object[] args) 
        throws Throwable { 
       if (Thread.interrupted()) { 
        throw new InterruptedException(); 
       } 
       return method.invoke(impl, args); 
      } 
     }); 
     return intf.cast(proxy); 
    } 
} 

interface Processes { 
    Object longProcess1(Object o); 
    ... 
} 

public class ProcessesImpl implement Processes { 
    Processes self = Wrapper.wrap(Processes.class, this); 

    public Object f(Object o1) { 
     Object o2 = self.longProcess1(o1); 
     Object o3 = self.longProcess2(o2); 
     return self.longProcess3(o3); 
    } 

    public Object longProcess1(Object o1) { 
     Object o2 = self.longSubProcess1(o1); 
     return self.longSubProcess2(o2); 
    } 

    .... 
} 
+0

दिलचस्प, लेकिन अभी भी थोड़ा बोझिल है। मुझे सभी प्रासंगिक वर्गों के लिए एक फ़ील्ड जोड़ने की आवश्यकता होगी, और कई विधि कॉल योग्य होंगे। परिणामस्वरूप विधियां * अधिक सुरुचिपूर्ण हैं, हालांकि, मैं आपको वह दूंगा! – Oak

0

मैं यह अधिकार है कि आप चलाने के तरीकों है कि एक ही नेस्टिंग स्तर पर हैं क्रमानुसार मिला? यदि ऐसा है, तो क्यों न केवल java.lang.Runnable उदाहरणों के रूप में अपनी गणना विधियों को लागू करें, उन्हें सूचियों में व्यवस्थित करें और उन्हें लूप में शुरू करें? फिर आपके पास Thread.interrupted() चेक के साथ केवल एक ही स्थान होगा।

आप गणना गणना कार्यों पर नियंत्रण की सुविधा के लिए java.util.concurrent.ExecutorService का उपयोग करने पर विचार कर सकते हैं।

एक उदाहरण के साथ अपडेट किया गया:

import java.util.ArrayList; 
import java.util.List; 

public class Test { 

    public static void main(String[] args) { 
     List<CompoundProcess> subProcesses1 = new ArrayList<CompoundProcess>(); 
     subProcesses1.add(new CompoundProcess() { 
      public void run() { 
       System.out.println("Process 1.1"); 
      } 
     }); 
     subProcesses1.add(new CompoundProcess() { 
      public void run() { 
       System.out.println("Process 1.2"); 
      } 
     }); 

     List<CompoundProcess> subProcesses2 = new ArrayList<CompoundProcess>(); 
     subProcesses2.add(new CompoundProcess() { 
      public void run() { 
       System.out.println("Process 2.1"); 
      } 
     }); 
     subProcesses2.add(new CompoundProcess() { 
      public void run() { 
       System.out.println("Process 2.2"); 
      } 
     }); 

     List<CompoundProcess> processes1 = new ArrayList<CompoundProcess>() {}; 
     processes1.add(new CompoundProcess(subProcesses1)); 
     processes1.add(new CompoundProcess(subProcesses2)); 

     CompoundProcess process = new CompoundProcess(processes1); 
     process.run(); 
    } 


    static class CompoundProcess implements Runnable { 

     private List<CompoundProcess> processes = new ArrayList<CompoundProcess>(); 

     public CompoundProcess() { 
     } 

     public CompoundProcess(List<CompoundProcess> processes) { 
      this.processes = processes; 
     } 

     public void run() { 
      for (Runnable process : processes) { 
       if (Thread.interrupted()) { 
        throw new RuntimeException("The processing was interrupted"); 
       } else { 
        process.run(); 
       } 
      } 
     } 
    } 

} 
+0

नहीं, प्रक्रियाएं कई अलग-अलग जगहों पर हैं - मैंने यह दिखाकर इसे प्रदर्शित करने की कोशिश की कि 'longProcess1' अपने आप में है, शायद मैं पर्याप्त स्पष्ट नहीं था - इसलिए मैंने स्पष्ट करने के लिए प्रश्न संपादित किया है। – Oak

+0

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

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