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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3929342/
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-14 07:03:42  来源:igfitidea点击:

Choose between ExecutorService's submit and ExecutorService's execute

javamultithreadingexecutorservice

提问by Cheok Yan Cheng

How should I choose between ExecutorService'ssubmitor execute, if the returned value is not my concern?

如果返回的值不是我所关心的,我应该如何在ExecutorService 的submitexecute之间进行选择?

If I test both, I didn't see any differences among the two except the returned value.

如果我同时测试两者,除了返回值之外,我没有发现两者之间有任何差异。

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


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

采纳答案by hochraldo

There is a difference concerning exception/error handling.

在异常/错误处理方面存在差异。

A task queued with execute()that generates some Throwablewill cause the UncaughtExceptionHandlerfor the Threadrunning the task to be invoked. The default UncaughtExceptionHandler, which typically prints the Throwablestack trace to System.err, will be invoked if no custom handler has been installed.

与排队的任务execute()是产生一些Throwable将导致UncaughtExceptionHandlerThread正在运行的任务被调用。如果未安装自定义处理程序,则将调用默认值UncaughtExceptionHandler(通常将Throwable堆栈跟踪打印到 )System.err

On the other hand, a Throwablegenerated by a task queued with submit()will bind the Throwableto the Futurethat was produced from the call to submit(). Calling get()on that Futurewill throw an ExecutionExceptionwith the original Throwableas its cause (accessible by calling getCause()on the ExecutionException).

另一方面,Throwable由排队的任务生成的 asubmit()将绑定ThrowableFuture调用产生的submit()。调用get()Future会抛出一个ExecutionException与原来的Throwable(通过调用访问作为其事业getCause()上的ExecutionException)。

回答by Syntax

Taken from the Javadoc:

摘自Javadoc:

Method submitextends base method {@link Executor#execute} by creating and returning a {@link Future} that can be used to cancel execution and/or wait for completion.

方法通过创建和返回可用于取消执行和/或等待完成的 {@link Future} 来submit扩展基本方法 {@link Executor# execute}。

Personally I prefer the use of execute because it feels more declarative, although this really is a matter of personal preference.

我个人更喜欢使用 execute ,因为它感觉更具声明性,尽管这确实是个人喜好的问题。

To give more information: in the case of the ExecutorServiceimplementation, the core implementation being returned by the call to Executors.newSingleThreadedExecutor()is a ThreadPoolExecutor.

提供更多信息:在实现的情况下,ExecutorService调用返回的核心实现Executors.newSingleThreadedExecutor()是 a ThreadPoolExecutor

The submitcalls are provided by its parent AbstractExecutorServiceand all call execute internally. execute is overridden/provided by the ThreadPoolExecutordirectly.

submit呼叫通过其母公司提供的AbstractExecutorService所有内部调用执行。execute 被ThreadPoolExecutor直接覆盖/提供。

回答by Steven

if you dont care about the return type, use execute. it's the same as submit, just without the return of Future.

如果您不关心返回类型,请使用执行。和 submit 一样,只是没有 Future 的返回。

回答by rxg

From the Javadoc:

Javadoc

The command may execute in a new thread, in a pooled thread, or in the calling thread, at the discretion of the Executor implementation.

根据 Executor 实现的判断,该命令可以在新线程、池线程或调用线程中执行。

So depending on the implementation of Executoryou may find that the submitting thread blocks while the task is executing.

因此,根据Executor您的实现,您可能会发现提交线程在任务执行时阻塞。

回答by Ravindra babu

execute: Use it for fire and forget calls

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

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

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

From javadocs

来自javadocs

submit(Callable<T> task)

submit(Callable<T> task)

Submits a value-returning task for execution and returns a Future representing the pending results of the task.

提交一个返回值的任务以供执行,并返回一个表示任务未决结果的 Future。

Future<?> submit(Runnable task)

Future<?> submit(Runnable task)

Submits a Runnable task for execution and returns a Future representing that task.

提交一个 Runnable 任务以供执行,并返回一个代表该任务的 Future。

void execute(Runnable command)

Executes the given command at some time in the future. The command may execute in a new thread, in a pooled thread, or in the calling thread, at the discretion of the Executor implementation.

在将来的某个时间执行给定的命令。根据 Executor 实现的判断,该命令可以在新线程、池线程或调用线程中执行。

You have to take precaution while using submit(). It hides exception in the framework itself unless you embed your task code in try{} catch{}block.

使用时一定要注意防范submit()。除非您将任务代码嵌入到try{} catch{}块中,否则它会在框架本身中隐藏异常。

Example code:This code swallows Arithmetic exception : / by zero.

示例代码:此代码吞下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();
    }
}

output:

输出:

java ExecuteSubmitDemo
creating service
a and b=4:0

Same code throws by replacing submit()with execute() :

通过替换submit()execute()会抛出相同的代码:

Replace

代替

service.submit(new Runnable(){

with

service.execute(new Runnable(){

output:

输出:

java ExecuteSubmitDemo
creating service
a and b=4:0
Exception in thread "pool-1-thread-1" java.lang.ArithmeticException: / by zero
        at ExecuteSubmitDemo.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)

How to handle the these type of scenarios while using submit()?

在使用 submit() 时如何处理这些类型的场景?

  1. Embed your Task code ( Either Runnable or Callable implementation) with try{} catch{} block code
  2. Implement CustomThreadPoolExecutor
  1. 使用 try{} catch{} 块代码嵌入您的任务代码(Runnable 或 Callable 实现)
  2. 实施 CustomThreadPoolExecutor

New solution:

新解决方案:

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);
   }
 }

output:

输出:

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

回答by alfasin

The full answer is a composition of two answers that were published here (plus a bit "extra"):

完整的答案是在这里发布的两个答案的组合(加上一点“额外”):

  • By submitting a task (vs. executing it) you get back a future which can be used to get the result or cancel the action. You don't have this kind of control when you execute(because its return type id void)
  • executeexpects a Runnablewhile submitcan take either a Runnableor a Callableas an argument (for more info about the difference between the two - see below).
  • executebubbles up any unchecked-exceptions right away (it cannot throw checked exceptions!!!), while submitbinds anykind of exception to the future that returns as a result, and only when you call future.get()a the (wrapped) exception will be thrown . The Throwable that you'll get is an instance of ExecutionExceptionand if you'll call this object's getCause()it will return the original Throwable.
  • 通过提交任务(与执行任务相比),您将获得一个可用于获取结果或取消操作的未来。你没有这种控制execute(因为它的返回类型 id void
  • execute期望一段Runnable时间submit可以将 aRunnable或 aCallable作为参数(有关两者之间差异的更多信息 - 请参见下文)。
  • execute立即冒泡任何未经检查的异常(它不能抛出已检查的异常!!!),同时submit任何类型的异常绑定到作为结果返回的未来,并且只有当您调用future.get()(包装的)异常时才会抛出。您将获得的 Throwable 是一个实例,ExecutionException如果您调用此对象getCause(),它将返回原始 Throwable。

A few more (related) points:

还有一些(相关)点:

  • Even if the task that you want to submitdoes not require returning a result, you can still use Callable<Void>(instead of using a Runnable).
  • Cancellation of tasks can be done using the interruptmechanism. Here's an exampleof how to implement a cancellation policy
  • 即使您想要的任务submit不需要返回结果,您仍然可以使用Callable<Void>(而不是使用 a Runnable)。
  • 可以使用中断机制取消任务。以下是如何实施取消政策的示例

To sum up, it's a better practice to use submitwith a Callable(vs. executewith a Runnable). And I'll quote from "Java concurrency in practice" By Brian Goetz:

总而言之,submit与 a Callable(vs. executewith a Runnable)一起使用是更好的做法。我将引用 Brian Goetz 的“实践中的 Java 并发”:

6.3.2 Result-bearing tasks: Callable and Future

The Executor framework uses Runnable as its basic task representation. Runnable is a fairly limiting abstraction; run cannot return a value or throw checked exceptions, although it can have side effects such as writing to a log file or placing a result in a shared data structure. Many tasks are effectively deferred computations—executing a database query, fetching a resource over the network, or computing a complicated function. For these types of tasks, Callable is a better abstraction: it expects that the main entry point, call, will return a value and anticipates that it might throw an exception.7 Executors includes several utility methods for wrapping other types of tasks, including Runnable and java.security.PrivilegedAction, with a Callable.

6.3.2 结果承载任务:Callable 和 Future

Executor 框架使用 Runnable 作为其基本任务表示。Runnable 是一个相当有限的抽象;run 不能返回值或抛出已检查的异常,尽管它可能会产生副作用,例如写入日志文件或将结果放入共享数据结构中。许多任务都是有效的延迟计算——执行数据库查询、通过网络获取资源或计算复杂的函数。对于这些类型的任务,Callable 是一个更好的抽象:它期望主入口点 call 将返回一个值并预计它可能会抛出异常。 7 Executors 包括几个用于包装其他类型任务的实用方法,包括 Runnable和 java.security.PrivilegedAction,带有一个 Callable。

回答by abhihello123

Just adding to the accepted answer-

只是添加到接受的答案 -

However, exceptions thrown from tasks make it to the uncaught exception handler only for tasks submitted with execute(); for tasks submitted with submit() to the executor service, any thrown exception is considered to be part of the task's return status.

但是,从任务抛出的异常只针对使用 execute() 提交的任务进入未捕获的异常处理程序;对于使用 submit() 提交给执行器服务的任务,任何抛出的异常都被视为任务返回状态的一部分。

Source

来源