ExecutorService के सबमिट और ExecutorService के निष्पादन के बीच चुनें


194

यदि मुझे लौटाया गया मूल्य मेरी चिंता का विषय नहीं है, तो मुझे एक्सकॉर्स्कोर सर्विस सबमिट या निष्पादित कैसे करना चाहिए ?

यदि मैं दोनों का परीक्षण करता हूं, तो मुझे दिए गए मान को छोड़कर दोनों में कोई अंतर नहीं दिखाई देता।

ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
threadExecutor.execute(new Task());

ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
threadExecutor.submit(new Task());

जवाबों:


204

अपवाद / त्रुटि हैंडलिंग से संबंधित एक अंतर है।

साथ पंक्तिबद्ध एक कार्य execute()है कि कुछ उत्पन्न Throwableकारण होगा UncaughtExceptionHandlerके लिए Threadकार्य चल रहा लागू किया जा करने के लिए। डिफ़ॉल्ट रूप से UncaughtExceptionHandler, जो आमतौर पर Throwableस्टैक ट्रेस को प्रिंट करता है System.err, यदि कोई कस्टम हैंडलर स्थापित नहीं किया गया है, तो इसे लागू किया जाएगा।

दूसरी ओर, एक Throwableकार्य से उत्पन्न एक पंक्ति जिसके साथ कॉल से उत्पादन किया गया था submit()के Throwableलिए बाध्य होगा । कॉलिंग उस पर एक फेंक होगा मूल के साथ (फोन करके सुलभ इसके कारण के रूप में पर )।Futuresubmit()get()FutureExecutionExceptionThrowablegetCause()ExecutionException


19
ध्यान दें कि इस व्यवहार की गारंटी नहीं है क्योंकि यह इस बात पर निर्भर करता है कि आपका Runnableलपेटा गया है Taskया नहीं, जिस पर आपका कोई नियंत्रण नहीं है। उदाहरण के लिए, यदि आपका Executorवास्तव में एक है ScheduledExecutorService, तो आपका कार्य आंतरिक रूप से एक में Futureलिपटेगा और अनकहा Throwableएस इस ऑब्जेक्ट के लिए बाध्य होगा।
आरएक्सजी

4
मेरा मतलब है 'लिपटे Futureया नहीं', बिल्कुल। उदाहरण के लिए, शेड्यूल्डड्रेडपूल एक्ज़ीक्यूटर # निष्पादित करने के लिए Javadoc देखें ।
आरएक्सजी

60

निष्पादित : यह आग और भूल कॉल के लिए उपयोग करें

सबमिट करें: विधि कॉल के परिणाम का निरीक्षण करने और कॉलFutureद्वारा लौटाए गए ऑब्जेक्टपर उचित कार्रवाई करने के लिए इसका उपयोगकरें

से javadocs

submit(Callable<T> task)

निष्पादन के लिए एक मूल्य-वापसी कार्य प्रस्तुत करता है और कार्य के लंबित परिणामों का प्रतिनिधित्व करते हुए एक भविष्य देता है।

Future<?> submit(Runnable task)

निष्पादन के लिए एक रनाने योग्य कार्य प्रस्तुत करता है और उस कार्य का प्रतिनिधित्व करने वाला भविष्य देता है।

void execute(Runnable command)

भविष्य में किसी समय दिए गए आदेश को निष्पादित करता है। आदेश क्रियान्वयन के विवेक पर, एक नए थ्रेड में, एक थ्रेडेड थ्रेड में या कॉलिंग थ्रेड में निष्पादित हो सकता है।

उपयोग करते समय आपको एहतियात बरतनी होगी submit()। जब तक आप अपने कार्य कोड को try{} catch{}ब्लॉक में एम्बेड नहीं करते हैं, तब तक यह फ्रेमवर्क में अपवाद को छिपा देता है।

उदाहरण कोड: यह कोड निगल जाता है Arithmetic exception : / by zero

import java.util.concurrent.*;
import java.util.*;

public class ExecuteSubmitDemo{
    public ExecuteSubmitDemo()
    {
        System.out.println("creating service");
        ExecutorService service = Executors.newFixedThreadPool(10);
        //ExtendedExecutor service = new ExtendedExecutor();
        service.submit(new Runnable(){
                 public void run(){
                    int a=4, b = 0;
                    System.out.println("a and b="+a+":"+b);
                    System.out.println("a/b:"+(a/b));
                    System.out.println("Thread Name in Runnable after divide by zero:"+Thread.currentThread().getName());
                 }
            });
        service.shutdown();
    }
    public static void main(String args[]){
        ExecuteSubmitDemo demo = new ExecuteSubmitDemo();
    }
}

उत्पादन:

java ExecuteSubmitDemo
creating service
a and b=4:0

() के submit()साथ प्रतिस्थापित करके समान कोड फेंकता है execute:

बदलने के

service.submit(new Runnable(){

साथ में

service.execute(new Runnable(){

उत्पादन:

java ExecuteSubmitDemo
creating service
a and b=4:0
Exception in thread "pool-1-thread-1" java.lang.ArithmeticException: / by zero
        at ExecuteSubmitDemo$1.run(ExecuteSubmitDemo.java:14)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:744)

सबमिट () का उपयोग करते समय इस प्रकार के परिदृश्यों को कैसे संभालें?

  1. प्रयास करें {} कैच {} ब्लॉक कोड के साथ अपना टास्क कोड ( या तो रन करने योग्य या कॉल करने योग्य कार्यान्वयन) को एम्बेड करें
  2. लागू CustomThreadPoolExecutor

नया समाधान:

import java.util.concurrent.*;
import java.util.*;

public class ExecuteSubmitDemo{
    public ExecuteSubmitDemo()
    {
        System.out.println("creating service");
        //ExecutorService service = Executors.newFixedThreadPool(10);
        ExtendedExecutor service = new ExtendedExecutor();
        service.submit(new Runnable(){
                 public void run(){
                    int a=4, b = 0;
                    System.out.println("a and b="+a+":"+b);
                    System.out.println("a/b:"+(a/b));
                    System.out.println("Thread Name in Runnable after divide by zero:"+Thread.currentThread().getName());
                 }
            });
        service.shutdown();
    }
    public static void main(String args[]){
        ExecuteSubmitDemo demo = new ExecuteSubmitDemo();
    }
}

class ExtendedExecutor extends ThreadPoolExecutor {

   public ExtendedExecutor() { 
       super(1,1,60,TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(100));
   }
   // ...
   protected void afterExecute(Runnable r, Throwable t) {
     super.afterExecute(r, t);
     if (t == null && r instanceof Future<?>) {
       try {
         Object result = ((Future<?>) r).get();
       } catch (CancellationException ce) {
           t = ce;
       } catch (ExecutionException ee) {
           t = ee.getCause();
       } catch (InterruptedException ie) {
           Thread.currentThread().interrupt(); // ignore/reset
       }
     }
     if (t != null)
       System.out.println(t);
   }
 }

उत्पादन:

java ExecuteSubmitDemo
creating service
a and b=4:0
java.lang.ArithmeticException: / by zero

अच्छा कुरकुरा स्पष्टीकरण। हालांकि इसका विस्तार करना वास्तव में आवश्यक नहीं है। यह जानने के लिए कि कार्य सफल था या नहीं, बस उस भविष्य की वस्तु का उपभोग करना होगा। इस प्रकार, सबमिट करें () का उपयोग करें यदि आप Future <t> का उपभोग करने की योजना बना रहे हैं, अन्यथा बस निष्पादित करें () का उपयोग करें
prash

11

यदि आप वापसी प्रकार के बारे में परवाह नहीं करते हैं, तो निष्पादन का उपयोग करें। यह भविष्य की वापसी के बिना, जमा के समान है।


15
स्वीकृत उत्तर के अनुसार यह सही नहीं है। अपवाद हैंडलिंग एक बहुत महत्वपूर्ण अंतर है।
जीरो 3

7

जवादोक से लिया गया:

विधि एक {@link फ्यूचर} बनाकर और वापस करके submitआधार विधि {@link एक्सक्लूसर # execute} का विस्तार करती है जिसका उपयोग निष्पादन और / या रद्द करने के लिए किया जा सकता है।

व्यक्तिगत रूप से मैं निष्पादन का उपयोग पसंद करता हूं क्योंकि यह अधिक घोषणात्मक लगता है, हालांकि यह वास्तव में व्यक्तिगत प्राथमिकता का मामला है।

अधिक जानकारी देने के लिए: ExecutorServiceकार्यान्वयन के मामले में , कॉल द्वारा वापस किया जा रहा कोर कार्यान्वयन Executors.newSingleThreadedExecutor()है ThreadPoolExecutor

submitकॉल इसके जनक द्वारा प्रदान की जाती हैं AbstractExecutorServiceऔर सभी कॉल आंतरिक रूप से निष्पादित करें। निष्पादन ThreadPoolExecutorसीधे द्वारा ओवरराइड / प्रदान किया जाता है।


2

से जावाडोक :

आदेश क्रियान्वयन के विवेक पर, एक नए थ्रेड में, एक थ्रेडेड थ्रेड में या कॉलिंग थ्रेड में निष्पादित हो सकता है।

तो Executorआप के कार्यान्वयन के आधार पर हो सकता है कि कार्य निष्पादित करते समय थ्रेड ब्लॉक जमा करना।


1

पूर्ण उत्तर दो उत्तरों की एक रचना है जो यहां प्रकाशित किए गए थे (प्लस थोड़ा "अतिरिक्त"):

  • किसी कार्य को सबमिट करने (बनाम इसे निष्पादित करने) से आपको एक भविष्य मिलता है जिसका उपयोग परिणाम प्राप्त करने या कार्रवाई को रद्द करने के लिए किया जा सकता है। आपके पास इस प्रकार का नियंत्रण नहीं है जब आप execute(क्योंकि इसकी वापसी प्रकार आईडी void)
  • executeएक उम्मीद Runnableहै, जबकि submitले जा सकते हैं या तो एक Runnableया एक Callableतर्क के रूप में (दोनों के बीच अंतर के बारे में अधिक जानकारी के लिए - नीचे देखें)।
  • executeकिसी भी अनियंत्रित-अपवाद को तुरंत बंद कर दें (यह जाँच किए गए अपवादों को फेंक नहीं सकता है !!!), जबकि भविष्य के किसी भी प्रकार के अपवाद को submitबांधता है , जिसके परिणामस्वरूप रिटर्न होता है, और केवल तब जब आप एक (लिपटे) अपवाद कहते हैं। आपको जो थ्रोबेबल मिलेगा, वह इसका एक उदाहरण है और यदि आप इस ऑब्जेक्ट को कॉल करेंगे तो यह मूल थ्रॉलेबल को लौटा देगा।future.get()ExecutionExceptiongetCause()

कुछ और (संबंधित) अंक:

  • यहां तक ​​कि अगर आप जिस कार्य को करना चाहते हैं submit, उसके परिणाम की वापसी की आवश्यकता नहीं है, तब भी आप Callable<Void>( उपयोग करने के बजाय Runnable) का उपयोग कर सकते हैं ।
  • रुकावट तंत्र का उपयोग करके कार्यों को रद्द किया जा सकता है । यहाँ एक उदाहरण है कि रद्द करने की नीति को कैसे लागू किया जाए

योग करने के लिए, submitएक Callable(बनाम के executeसाथ Runnable) का उपयोग करना बेहतर अभ्यास है । और मैं ब्रायन गोएत्ज़ द्वारा "जावा कंसीडर इन प्रैक्टिस" उद्धृत करूंगा:

6.3.2 परिणाम-असर कार्य: कॉल करने योग्य और भविष्य

एक्ज़ीक्यूटर फ्रेमवर्क अपने मूल कार्य प्रतिनिधित्व के रूप में रननेबल का उपयोग करता है। Runnable एक काफी सीमित अमूर्तता है; रन वैल्यू को वापस नहीं ला सकता है या चेक किए गए अपवादों को नहीं फेंक सकता है, हालांकि इसके साइड इफेक्ट्स हो सकते हैं जैसे लॉग फाइल पर लिखना या किसी साझा डेटा संरचना में परिणाम देना। कई कार्यों को प्रभावी ढंग से गणनाओं को स्थगित कर दिया जाता है - एक डेटाबेस क्वेरी निष्पादित करना, नेटवर्क पर एक संसाधन प्राप्त करना, या एक जटिल फ़ंक्शन की गणना करना। इन प्रकार के कार्यों के लिए, कॉल करने योग्य एक बेहतर अमूर्तता है: यह उम्मीद करता है कि मुख्य प्रवेश बिंदु, कॉल, एक मूल्य लौटाएगा और अनुमान लगाता है कि यह एक अपवाद फेंक सकता है। निष्पादनकर्ताओं में रननेबल सहित अन्य प्रकार के कार्यों को लपेटने के लिए कई उपयोगिता विधियां शामिल हैं। और java.security.PrivilegedAction, एक कॉल करने योग्य के साथ।


1

स्वीकार किए गए जवाब में बस जोड़ना-

हालांकि, कार्यों से फेंके गए अपवाद केवल निष्पादित निष्पादन के साथ प्रस्तुत किए गए कार्यों के लिए अनकैप्ड अपवाद हैंडलर को बनाते हैं; प्रस्तुतकर्ता सेवा को सबमिट () के साथ सबमिट किए गए कार्यों के लिए, किसी भी फेंके गए अपवाद को कार्य की वापसी स्थिति का हिस्सा माना जाता है।

स्रोत

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.