设为首页 加入收藏

TOP

线程池execute 和 submit 的区别(一)
2023-07-25 21:33:01 】 浏览:39
Tags:程池 execute submit

1. executesubmit 的区别

前面说了还需要介绍多线程中使用 executesubmit 的区别(这两个方法都是线程池 ThreadPoolExecutor 的方法)。

1.1 方法来源不同

execute 方法是线程池的顶层接口 Executor 定义的,在 ThreadPoolExecutor 中实现:

void execute(Runnable command);

submit()是在ExecutorService接口中定义的,并定义了三种重载方式:

<T> Future<T> submit(Callable<T> task);

<T> Future<T> submit(Runnable task, T result);

Future<?> submit(Runnable task);

AbstractExecutorService类中有它们的具体实现,而ThreadPoolExecutor继承了AbstractExecutorService类。所以 ThreadPoolExecutor 也有这三个方法。

1.2 接收参数不同

从上面的方法来源中可以看出,二者接收参数类型不同:

  1. execute()方法只能接收实现Runnable接口类型的任务
  2. submit()方法则既可以接收Runnable类型的任务,也可以接收Callable类型的任务

1.3 返回值不同

由于 RunnableCallable 的区别就是,Runnable 无返回值,Callable 有返回值。

所以 executesubmit 的返回值也不同。

  1. execute()的返回值是void,线程提交后不能得到线程的返回值

  2. submit()的返回值是Future,通过Future的get()方法可以获取到线程执行的返回值,get()方法是同步的,执行get()方法时,如果线程还没执行完,会同步等待,直到线程执行完成

    虽然submit()方法可以提交Runnable类型的参数,但执行Future方法的get()时,线程执行完会返回null,不会有实际的返回值,这是因为Runable本来就没有返回值
    

1.4 异常处理机制不同

  1. submit 提交任务,任务内有异常也不会打印异常信息,而是调用get()方法时,打印出任务执行异常信息
  2. execute 提交任务时,任务内有异常会直接打印出来

后面源码分析中会体现这个不同点!

2. executesubmit 源码分析

2.1 submit 源码分析

submit 方法是 ExecutorService 接口定义,由 AbstractExecutorService 抽象类实现,有三个重载方法:

public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<Void> ftask = newTaskFor(task, null);
    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;
}

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

可以看一下上面 submit 的三个重载方法,方法体很相似,都调用了一个方法 newTaskFor(...) ,那么就来看看这个方法,可以看到它有两个重载方法:

protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
    return new FutureTask<T>(runnable, value);
}

protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
    return new FutureTask<T>(callable);
}

解释一下上面两个重载方法吧:

  1. 第一个newTaskFor(Runnable runnable, T value):可以看到它应该是将 submit 方法传进来的 Runnable 转化成了 Callable,并给一个返回值
  2. 第二个newTaskFor(Callable<T> callable):就是submit直接传进了一个 Callable,包装成 FutureTask 返回。

上面代码中可以看一下 RunnableFutureFutureTask 的关系:

先看一下 RunnableFuture:
public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();
}
RunnableFuture 实现了 Runnable 和 Future,它的子类就是 FutureTask
    
public class FutureTask<V> implements RunnableFuture<V> {
    // ...
}

到这里就明白了吧,当 submit 传入的参数是 Runnable 的时候,就需要 FutureTask的构造方法将 Runnable 转化成 Callable

下面看一下 FutureTask 的两个构造函数:

// 传入Runnable则是执行了一共方法,看一下这个方法,具体转化逻辑就有了
public FutureTask(Runnable runnable, V result) {
    this.callable = Executors.callable(runnable, result);
    this.state = NEW;       // ensure visibility of callable
}

// 传入Callable直接赋值给类的成员变量
public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable;
    this.state = NEW;       // ensure visibility of callable
}

下面看一下当 submit 传入 Runnable 的时候,其实到这里就是调用了 FutureTask(Runnable r

首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Springfox与SpringDoc——swagger.. 下一篇Java性能权威指南(第2版)读后总..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目