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

pgx2nnw8  于 2023-05-05  发布在  Java
关注(0)|答案(7)|浏览(214)

如果返回值不是我关心的,我应该如何选择ExecutorService的submit还是execute?
如果我同时测试这两种方法,除了返回值之外,我看不到两者之间的任何区别。

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

u1ehiz5o1#

在异常/错误处理方面存在差异。
execute()一起排队的任务生成一些Throwable,将导致运行该任务的ThreadUncaughtExceptionHandler被调用。默认的UncaughtExceptionHandler通常会将Throwable堆栈跟踪打印到System.err,如果没有安装自定义处理程序,则将调用该默认的UncaughtExceptionHandler
另一方面,与submit()一起排队的任务生成的Throwable将把Throwable绑定到调用submit()生成的Future。在Future上调用get()将抛出一个ExecutionException,其原因是原始Throwable(通过在ExecutionException上调用getCause()来访问)。

f8rj6qna

f8rj6qna2#

执行:用它来生火和忘记电话

来自ExecutorService,作者docs.oracle.com

提交:

方法submit通过创建和返回一个Future来扩展基本方法Executor.execute(Runnable),Future可用于取消执行和/或等待完成
submit(Callable<T> task)
提交一个返回值的任务以供执行,并返回一个Future,表示任务的挂起结果。
Future<?> submit(Runnable task)
提交Runnable任务以供执行,并返回表示该任务的Future。

void execute(Runnable command)

在将来的某个时间执行给定的命令。该命令可以在新线程、池线程或调用线程中执行,具体由Executor实现决定。
在使用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)

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

1.使用try{} catch{}块代码嵌入任务代码(* Runnable或Callable实现)*
1.使用ExtendedExecutor类处理afterExecute方法,按照docs.oracle.comThreadPoolExecutor中的说明实现CustomThreadPoolExecutor

新方案:

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
7eumitmz

7eumitmz3#

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

0h4hbjxa

0h4hbjxa4#

在Javadoc中:
方法submit通过创建和返回一个{@link Future}来扩展基方法{@link Executor#execute},该{@link Future}可用于取消执行和/或等待完成。
就我个人而言,我更喜欢使用execute,因为它感觉更具有声明性,尽管这实际上是个人偏好的问题。
给予更多信息:在ExecutorService实现的情况下,调用Executors.newSingleThreadedExecutor()返回的核心实现是ThreadPoolExecutor
submit调用由其父AbstractExecutorService提供,所有调用都在内部执行。execute由ThreadPoolExecutor直接覆盖/提供。

bvjveswy

bvjveswy5#

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

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

更多(相关):

  • 即使你想要submit的任务不需要返回结果,你仍然可以使用Callable<Void>(而不是使用Runnable)。
  • 可以使用interrupt机制取消任务。以下是如何实施取消政策的an example

总而言之,将submitCallable一起使用是一种更好的做法(而不是将submitCallable一起使用)。executeRunnable)。我将引用Brian Goetz的“Java并发性实践”:

6.3.2结果任务:可赎回和未来

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

e4yzc0pl

e4yzc0pl6#

在Javadoc中:
该命令可以在新线程、池线程或调用线程中执行,具体由Executor实现决定。
因此,根据Executor的实现,您可能会发现提交线程在任务执行时阻塞。

2w3rbyxf

2w3rbyxf7#

只是补充一下公认的答案-
但是,从任务中抛出的异常只有在用execute()提交的任务中才会进入未捕获异常处理程序;对于使用submit()提交给executor服务的任务,任何抛出的异常都被认为是任务返回状态的一部分。
Source

相关问题