Java 中这段代码中的 ExecutorService.submit 和 ExecutorService.execute 有什么区别?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18730290/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 10:33:02  来源:igfitidea点击:

What is the difference between ExecutorService.submit and ExecutorService.execute in this code in Java?

javamultithreadingthreadpoolexecutorservice

提问by brain storm

I am learning to use ExectorServiceto pool threadsand send out tasks. I have a simple program below

我正在学习使用ExectorServicethreads和发送任务。我在下面有一个简单的程序

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;


class Processor implements Runnable {

    private int id;

    public Processor(int id) {
        this.id = id;
    }

    public void run() {
        System.out.println("Starting: " + id);

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            System.out.println("sorry, being interupted, good bye!");
            System.out.println("Interrupted " + Thread.currentThread().getName());
            e.printStackTrace();
        }

        System.out.println("Completed: " + id);
    }
}


public class ExecutorExample {

    public static void main(String[] args) {
        Boolean isCompleted = false;

        ExecutorService executor = Executors.newFixedThreadPool(2);

        for (int i = 0; i < 5; i++) {
            executor.execute(new Processor(i));
        }

        //executor does not accept any more tasks but the submitted tasks continue
        executor.shutdown();

        System.out.println("All tasks submitted.");

        try {
            //wait for the exectutor to terminate normally, which will return true
            //if timeout happens, returns false, but this does NOT interrupt the threads
            isCompleted = executor.awaitTermination(100, TimeUnit.SECONDS);
            //this will interrupt thread it manages. catch the interrupted exception in the threads
            //If not, threads will run forever and executor will never be able to shutdown.
            executor.shutdownNow();
        } catch (InterruptedException e) {
        }

        if (isCompleted) {
            System.out.println("All tasks completed.");
        } else {
            System.out.println("Timeout " + Thread.currentThread().getName());
        }
    }
}

It does nothing fancy, but creates two threadsand submits 5 tasks in total. After each threadcompletes its task, it takes the next one, In the code above, I use executor.submit. I also changed to executor.execute. But I do not see any difference in the output. In what way are the submitand executemethods different? This what the APIsays

它没有什么特别的,但是创建了两个threads并总共提交了 5 个任务。每个thread完成它的任务后,它需要下一个,在上面的代码中,我使用executor.submit. 我也改成executor.execute。但我看不出输出有什么不同。submitexecute方法有什么不同?这就是API所说的

Method submit extends base method Executor.execute(java.lang.Runnable) by creating and returning a Future that can be used to cancel execution and/or wait for completion. Methods invokeAny and invokeAll perform the most commonly useful forms of bulk execution, executing a collection of tasks and then waiting for at least one, or all, to complete. (Class ExecutorCompletionService can be used to write customized variants of these methods.)

方法 submit 通过创建和返回可用于取消执行和/或等待完成的 Future 来扩展基本方法 Executor.execute(java.lang.Runnable)。方法 invokeAny 和 invokeAll 执行最常用的批量执行形式,执行一组任务,然后等待至少一个或全部完成。(类 ExecutorCompletionService 可用于编写这些方法的自定义变体。)

But it's not clear to me as what it exactly means?

但我不清楚它到底意味着什么?

采纳答案by dkatzel

As you see from the JavaDoc execute(Runnable)does not return anything.

正如您从 JavaDocexecute(Runnable)中看到的,不返回任何内容。

However, submit(Callable<T>)returns a Futureobject which allows a way for you to programatically cancel the running thread later as well as get the Tthat is returned when the Callablecompletes. See JavaDoc of Futurefor more details

但是,submit(Callable<T>)返回一个Future对象,它允许您稍后以编程方式取消正在运行的线程以及获取完成T时返回的对象Callable。有关更多详细信息,请参阅JavaDoc of Future

Future<?> future = executor.submit(longRunningJob);
...
//long running job is taking too long
future.cancel(true);

Moreover, if future.get() == nulland doesn't throw any exception then Runnable executed successfully

此外,如果future.get() == null并且不抛出任何异常,那么 Runnable 执行成功

回答by tbodt

The difference is that executesimply starts the task without any further ado, whereas submitreturns a Futureobject to manage the task. You can do the following things with the Futureobject:

不同之处在于,它execute只是简单地启动任务,而不用任何麻烦,而submit返回一个Future对象来管理任务。您可以对Future对象执行以下操作:

  • Cancel the task prematurely, with the cancelmethod.
  • Wait for the task to finish executing, with get.
  • 提前取消任务,使用cancel方法。
  • 等待任务完成执行,使用get.

The Futureinterface is more useful if you submit a Callableto the pool. The return value of the callmethod will be returned when you call Future.get. If you don't maintain a reference to the Future, there is no difference.

Future如果您将 a 提交Callable到池,则该界面会更有用。call调用时会返回该方法的返回值Future.get。如果您不维护对 的引用Future,则没有区别。

回答by Preetham R U

Submit - Returns Future object, which can be used to check result of submitted task. Can be used to cancel or to check isDone etc.

Submit - 返回 Future 对象,可用于检查提交任务的结果。可用于取消或检查 isDone 等。

Execute - doesn't return anything.

执行 - 不返回任何内容。

回答by Ravindra babu

execute:Use it for fire and forget calls

execute:将其用于火灾和忘记电话

submit:Use it to inspect the result of method call and take appropriate action on Futureobjected returned by the call

submit:使用它来检查方法调用的结果并对调用Future返回的对象采取适当的行动

Major difference: Exceptionhandling

主要区别:Exception处理

submit()hides un-handled Exceptionin framework itself.

submit()隐藏Exception在框架本身中未处理。

execute()throws un-handled Exception.

execute()抛出未处理Exception

Solution for handling Exceptions with submit()

处理异常的解决方案 submit()

  1. Wrap your Callable or Runnable code in try{} catch{} block

    OR

  2. Keep future.get() call in try{} catch{} block

    OR

  3. implement your own ThreadPoolExecutorand override afterExecutemethod

  1. 包裹你的 Callable or Runnable code in try{} catch{} block

    或者

  2. 保持 future.get() call in try{} catch{} block

    或者

  3. 实现你自己的ThreadPoolExecutor和覆盖afterExecute方法

Regarding tour other queries on

关于旅游的其他问题

invokeAll:

调用所有

Executes the given tasks, returning a list of Futures holding their status and results when all complete or the timeout expires, whichever happens first.

执行给定的任务,当全部完成或超时到期时,返回一个保存其状态和结果的 Futures 列表,以先发生者为准。

invokeAny:

调用任何

Executes the given tasks, returning the result of one that has completed successfully (i.e., without throwing an exception), if any do before the given timeout elapses.

执行给定的任务,返回已成功完成的任务的结果(即,不抛出异常),如果在给定的超时时间过去之前执行任何操作。

Use invokeAllif you want to wait for all submitted tasks to complete.

使用invokeAll,如果你想等待所有提交的任务来完成。

Use invokeAnyif you are looking for successful completion of one task out of N submitted tasks. In this case, tasks in progress will be cancelled if one of the tasks completes successfully.

使用invokeAny,如果你正在寻找一个任务的圆满完成了N个提交的任务。在这种情况下,如果其中一项任务成功完成,正在进行的任务将被取消。

Related post with code example:

与代码示例相关的帖子:

Choose between ExecutorService's submit and ExecutorService's execute

在 ExecutorService 的提交和 ExecutorService 的执行之间进行选择

回答by amarnath harish

basically both calls execute,if u want future object you shall call submit() method here from the doc

基本上两个调用都执行,如果你想要未来的对象,你应该从文档中调用 submit() 方法

public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task);
    execute(ftask);
    return ftask;
}


public <T> Future<T> submit(Runnable task, T result) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task, result);
    execute(ftask);
    return ftask;
}

as you can see java really has no way to start a thread other than calling run() method, IMO. since i also found that Callable.call()method is called inside run()method. hence if the object is callable it would still call run()method, which inturn would call call()method from doc.

正如你所看到的,除了调用 run() 方法,IMO 之外,java 真的没有办法启动一个线程。因为我还发现该Callable.call()方法被称为内部run()方法。因此,如果对象是可调用的,它仍然会调用run()方法,而call()方法又会从 doc调用方法。

public void run() {
    if (state != NEW ||
        !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                     null, Thread.currentThread()))
        return;
    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;
                setException(ex);
            }
            if (ran)
                set(result);
        }
    } finally {
        // runner must be non-null until state is settled to
        // prevent concurrent calls to run()
        runner = null;
        // state must be re-read after nulling runner to prevent
        // leaked interrupts
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}

回答by amitkumar12788

A main difference between the submit() and execute() method is that ExecuterService.submit()can return result of computation because it has a return type of Future, but execute() method cannot return anything because it's return type is void. The core interface in Java 1.5's Executor framework is the Executor interface which defines the execute(Runnable task) method, whose primary purpose is to separate the task from its execution.

submit() 和 execute() 方法的主要区别在于,ExecuterService.submit() 可以返回计算结果,因为它的返回类型为 Future,而 execute() 方法不能返回任何内容,因为它的返回类型为 void。Java 1.5 Executor 框架中的核心接口是Executor 接口,它定义了execute(Runnable task) 方法,其主要目的是将任务与其执行分离。

Any task submitted to Executor can be executed by the same thread, a worker thread from a thread pool or any other thread.

任何提交给 Executor 的任务都可以由同一个线程、线程池中的工作线程或任何其他线程执行。

On the other hand, submit() method is defined in the ExecutorService interface which is a sub-interface of Executor and adds the functionality of terminating the thread pool, along with adding submit() method which can accept a Callable task and return a result of computation.

另一方面,在Executor的子接口ExecutorService接口中定义了submit()方法,增加了终止线程池的功能,同时增加了submit()方法,可以接受Callable任务并返回结果的计算。

Similarities between the execute() and submit() as well:

execute() 和 submit() 之间也有相似之处:

  1. Both submit() and execute() methods are used to submit a task to Executor framework for asynchronous execution.
  2. Both submit() and execute() can accept a Runnable task.
  3. You can access submit() and execute() from the ExecutorService interface because it also extends the Executor interface which declares the execute() method.
  1. submit() 和 execute() 方法都用于将任务提交给 Executor 框架进行异步执行。
  2. submit() 和 execute() 都可以接受 Runnable 任务。
  3. 您可以从 ExecutorService 接口访问 submit() 和 execute() 因为它也扩展了声明 execute() 方法的 Executor 接口。

Apart from the fact that submit() method can return output and execute() cannot, following are other notable differences between these two key methods of Executor framework of Java 5.

除了 submit() 方法可以返回输出而 execute() 不能返回这一事实之外,以下是 Java 5 Executor 框架的这两个关键方法之间的其他显着差异。

  1. The submit() can accept both Runnable and Callable task but execute() can only accept the Runnable task.
  2. The submit() method is declared in ExecutorService interface while execute() method is declared in the Executor interface.
  3. The return type of submit() method is a Future object but return type of execute() method is void.
  1. submit() 可以接受 Runnable 和 Callable 任务,但 execute() 只能接受 Runnable 任务。
  2. submit() 方法在 ExecutorService 接口中声明,而 execute() 方法在 Executor 接口中声明。
  3. submit() 方法的返回类型是 Future 对象,而 execute() 方法的返回类型是 void。

回答by Koray Tugay

If you check the source code, you will see that submitis sort of a wrapper on execute

如果您检查源代码,您会发现它submit有点像execute

public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<Void> ftask = newTaskFor(task, null);
    execute(ftask);
    return ftask;
}