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

问题描述 投票:0回答:6

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

如果我测试两者,除了返回值外,我没有看到两者之间有任何差异。

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

ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
threadExecutor.submit(new Task());
java multithreading executorservice
6个回答
219
投票

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

与生成一些

execute()
Throwable
一起排队的任务将导致调用运行任务的
UncaughtExceptionHandler
Thread
。默认的
UncaughtExceptionHandler
,通常将
Throwable
堆栈跟踪打印到
System.err
,如果没有安装自定义处理程序,将被调用。

另一方面,由使用

Throwable
排队的任务生成的
submit()
会将
Throwable
绑定到从调用
Future
生成的
submit()
。在那个
get()
上调用
Future
将抛出一个
ExecutionException
以原来的
Throwable
作为它的原因(通过在
getCause()
上调用
ExecutionException
访问)。


13
投票

如果你不关心返回类型,使用execute。它和提交一样,只是没有 Future 的返回。


8
投票

取自Javadoc:

方法

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

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

提供更多信息:在

ExecutorService
实现的情况下,调用
Executors.newSingleThreadedExecutor()
返回的核心实现是
ThreadPoolExecutor
.

submit
调用由其父级
AbstractExecutorService
提供,所有调用都在内部执行。 execute 被
ThreadPoolExecutor
直接覆盖/提供。


4
投票

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

  • 通过提交一个任务(相对于执行它)你会得到一个可以用来获取结果或取消操作的未来。当你
    execute
    (因为它的返回类型id
    void
  • 时,你没有这种控制
  • execute
    期望
    Runnable
    submit
    可以采用
    Runnable
    Callable
    作为参数(有关两者之间差异的更多信息 - 请参见下文)。
  • execute
    立即冒出任何未经检查的异常(它不能抛出已检查的异常!!!),而
    submit
    任何 类型的异常绑定到作为结果返回的未来,并且仅当您调用
    future.get() 
    将抛出(包装的)异常。您将获得的 Throwable 是
    ExecutionException
    的一个实例,如果您调用此对象的
    getCause()
    它将返回原始 Throwable。

更多(相关)点:

  • 即使你想要
    submit
    的任务不需要返回一个 结果,您仍然可以使用
    Callable<Void>
    (而不是使用
    Runnable
    )。
  • 可以使用中断机制取消任务。这是如何实施取消政策的示例

总而言之,将

submit
Callable
结合使用是更好的做法(相对于
execute
Runnable
)。我将引用 Brian Goetz 的“Java 并发实践”:

6.3.2 Result-bearing tasks: Callable and Future

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


2
投票

来自Javadoc

命令可以在新线程、池线程或调用线程中执行,由 Executor 实现自行决定。

因此,根据

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


1
投票

只需添加到已接受的答案-

然而,从任务中抛出的异常使其成为未捕获的 仅适用于使用 execute() 提交的任务的异常处理程序;对于任务 使用 submit() 提交给执行程序服务,任何抛出的异常 被认为是任务返回状态的一部分。

来源

© www.soinside.com 2019 - 2024. All rights reserved.