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

发布于 2024-09-27 08:39:18 字数 674 浏览 8 评论 0原文

我应该如何在 ExecutorService 的 提交执行,如果返回值不是我关心的?

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

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

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

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

み零 2024-10-04 08:39:18

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

使用 execute() 排队并生成一些 Throwable 的任务将导致运行该任务的 ThreadUncaughtExceptionHandler被调用。如果尚未安装自定义处理程序,将调用默认的 UncaughtExceptionHandler 通常会将 Throwable 堆栈跟踪打印到 System.err

另一方面,由使用 submit() 排队的任务生成的 Throwable 会将 Throwable 绑定到 Future > 这是通过调用 submit() 生成的。在该 Future 上调用 get() 将抛出一个 ExecutionException,其原因是原始的 Throwable(可通过调用ExecutionException 上的 getCause())。

There is a difference concerning exception/error handling.

A task queued with execute() that generates some Throwable will cause the UncaughtExceptionHandler for the Thread running the task to be invoked. The default UncaughtExceptionHandler, which typically prints the Throwable stack trace to System.err, will be invoked if no custom handler has been installed.

On the other hand, a Throwable generated by a task queued with submit() will bind the Throwable to the Future that was produced from the call to submit(). Calling get() on that Future will throw an ExecutionException with the original Throwable as its cause (accessible by calling getCause() on the ExecutionException).

删除→记忆 2024-10-04 08:39:18

执行:使用它进行即发即忘调用,

来自 ExecutorService 作者:docs.oracle.com

提交:

方法submit通过创建并返回可用于取消执行和/或等待完成的Future来扩展基本方法Executor.execute(Runnable)

submit(Callabletask)

提交一个有返回值的任务执行并返回一个Future
代表任务的待处理结果。

未来提交(可运行任务)

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

void execute(Runnable command)

在将来的某个时间执行给定的命令。该命令可以在新线程、池线程或调用线程中执行,具体取决于 Executor 实现。

使用 submit() 时必须采取预防措施。除非您将任务代码嵌入到 try{} catch{} 块中,否则它会将异常隐藏在框架本身中。

示例代码:此代码吞掉算术异常:/ 为零

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. 使用 try{} catch{} 块代码嵌入您的任务代码(Runnable 或 Callable 实现)
  2. 实现 CustomThreadPoolExecutor,如中所述ThreadPoolExecutor 作者:docs .oracle.com 具有 ExtendedExecutor 类处理 afterExecute 方法

新解决方案:

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

public class ExecuteSubmitDemo{
    public ExecuteSubmitDemo()
    {
        System.out.println("creating service");
        //ExecutorService service = Executors.newFixedThreadPool(10);
        /* Refer to linked Oracle documentation page for ExtendedExecutor  source code */
        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
java.lang.ArithmeticException: / by zero

execute: Use it for fire and forget calls

From ExecutorService by docs.oracle.com

submit:

Method submit extends base method Executor.execute(Runnable) by creating and returning a Future that can be used to cancel execution and/or wait for completion

submit(Callable<T> task)

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

Future<?> submit(Runnable task)

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

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.

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.

Example code: This code swallows 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() :

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$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)

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

  1. Embed your Task code ( Either Runnable or Callable implementation) with try{} catch{} block code
  2. Implement CustomThreadPoolExecutor as explained in ThreadPoolExecutor by docs.oracle.com with ExtendedExecutor class handling afterExecute method

New solution:

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

public class ExecuteSubmitDemo{
    public ExecuteSubmitDemo()
    {
        System.out.println("creating service");
        //ExecutorService service = Executors.newFixedThreadPool(10);
        /* Refer to linked Oracle documentation page for ExtendedExecutor  source code */
        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
java.lang.ArithmeticException: / by zero
玩世 2024-10-04 08:39:18

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

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

因为看清所以看轻 2024-10-04 08:39:18

摘自 Javadoc:

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

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

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

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

Taken from the Javadoc:

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

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

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

The submit calls are provided by its parent AbstractExecutorService and all call execute internally. execute is overridden/provided by the ThreadPoolExecutor directly.

ぇ气 2024-10-04 08:39:18

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

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

还有一些(相关)点:

  • 即使您要提交的任务不需要返回
    结果,您仍然可以使用Callable(而不是使用Runnable)。
  • 可以使用中断机制来取消任务。以下是如何实施取消政策的示例

总而言之,使用submit是更好的做法code> 与 Callable(与 executeRunnable)。我将引用 Brian Goetz 的《Java 并发实践》:

6.3.2 结果承载任务:Callable 和 Future

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

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)
  • execute expects a Runnable while submit can take either a Runnable or a Callable as an argument (for more info about the difference between the two - see below).
  • execute bubbles up any unchecked-exceptions right away (it cannot throw checked exceptions!!!), while submit binds any kind 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 ExecutionException and if you'll call this object's getCause() it will return the original Throwable.

A few more (related) points:

  • Even if the task that you want to submit does not require returning a
    result, you can still use Callable<Void> (instead of using a Runnable).
  • Cancellation of tasks can be done using the interrupt mechanism. Here's an example of how to implement a cancellation policy

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

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.

后来的我们 2024-10-04 08:39:18

execute 可能会也可能不会使用

来自 Javadoc

该命令可以在新线程、池线程或调用线程中执行,具体由执行器实现决定。

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

为了确保您的任务在另一个线程上运行,请勿调用 执行。相反,请调用 提交, invokeAll ,或 invokeAny

execute may, or may not, use another thread

From the 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.

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

To be sure your task runs on another thread, do not call execute. Instead, call submit, invokeAll, or invokeAny.

软糖 2024-10-04 08:39:18

只是添加到已接受的答案中 -

但是,任务抛出的异常会导致未被捕获
异常处理程序仅适用于使用execute()提交的任务;用于任务
使用submit()提交给执行器服务,任何抛出的异常
被视为任务返回状态的一部分。

来源

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.

Source

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文