一、结论

  • 基本没有区别,在submit方法中仍然是调用的execute方法进行任务的执行或进入等待队列或拒绝。
  • submit方法比execute方法多的只是将提交的任务(不管是runnable类型还是callable类型)包装成RunnableFuture然后传递给execute方法执行。
  • submit方法和execute方法最大的不同点在于submit方法可以获取到任务返回值或任务异常信息,execute方法不能获取任务返回值和异常信息。
  • RunnableFuture从名字就可以知道,他既是一个Runnable又是一个Future,所以说submit方法提交的任务被包装成RunnableFuture后,后面执行任务的时候运行的就是RunnableFuture.run()方法,所以最根本的区别在RunnableFuture.run()方法里。所以这里才是重点关注的地方。

二、源码对比

①、execute源码
public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    
    int c = ctl.get();
  	// 【 1 】、worker数量比核心线程数小,直接创建worker执行任务
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
  	// 【 2 】、worker数量超过核心线程数,任务直接进入队列。
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        if (! isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
  	//【 3 】、 如果线程池不是运行状态,或者任务进入队列失败,则尝试创建worker执行任务(即:线程阻塞队列满了但
  	// 线程池中的线程数没达到最大线程数,则新开启一个线程去执行该任务)。
    else if (!addWorker(command, false))
        reject(command);
}
②、submit源码
public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
  	// 将提交的runnable任务包装成RunnableFuture
    RunnableFuture<Void> ftask = newTaskFor(task, null);
    execute(ftask);
    return ftask;
}

// 将提交的runnable任务包装成RunnableFuture
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;
}

// 将提交的callable任务包装成RunnableFuture
public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task);
    execute(ftask);
    return ftask;
}

从上面的源码对比中可以看到,submit方法比execute方法多的只是将提交的任务(不管是runnable类型还是callable类型)包装成RunnableFuture,其核心逻辑还是调用的execute方法执行。

③、RunnableFuture.run方法

可以看到RunnableFuture是一个接口,该接口基继承了Runnable, Future。其实现类主要看FutureTask

public interface RunnableFuture<V> extends Runnable, Future<V> {
    
    void run();
  
}

FutureTask

// 可以看到FutureTask实现了RunnableFuture接口
public class FutureTask<V> implements RunnableFuture<V> {
  
    public void run() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
          	// 1、状态检查
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                  	// 2、调用包装前的实际方法执行并获取返回值
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                  	// 3、如果执行失败,则保存异常信息
                    result = null;
                    ran = false;
                    setException(ex);
                }
              	// 4、如果执行成功,则将返回值保存起来
                if (ran)
                    set(result);
            }
        } finally {
            runner = null;
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }
  
}

从FutureTask的源码中可以看出,submit方法将提交的任务包装成RunnableFuture以后,当该任务被执行的时候实际上执行的是RunnableFuture的run方法,在这个run方法里调用了原来的任务方法执行,并且获取到返回值并且保存起来。

也就是说submit方法和execute方法最大的不同点在于submit方法可以获取到任务返回值或任务异常信息,execute方法不能获取任务返回值和异常信息。

GitHub 加速计划 / th / ThreadPool
7.74 K
2.22 K
下载
A simple C++11 Thread Pool implementation
最近提交(Master分支:2 个月前 )
9a42ec13 - 9 年前
fcc91415 - 9 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐