Java线程池execute与submit的联系与区别

221 阅读2分钟

Java线程池execute与submit的联系与区别

先放两张类的继承实现图

在说 submit 与 execute 之前先了解一些类之间的关系

FutureTask.png

ThreadPoolExecutor.png

ThreadPoolExecutor.png

所以 FutureTask 是 Runnable 的子类,并且 FutureTask 有一个私有变量private Callable<V> callable;

前面两点很重要,FutureTask 继承来的 run 方法中是 执行了 private Callable<V> callablecall()方法,并且把返回值的引用保存下来。

public void run() {
       。。。
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    。。。。
                }
                if (ran)
                    set(result);
            }
        } finally {
           。。。
        }
    }

submit 与 execute的具体实现

execute 是在 Executor 接口中定义,在ThreadPoolExecutor 类中实现。

submit 是在 ExecutorService 接口中定义,在 AbstractExecutorService 抽象类中实现。 并且有三种重载实现:

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

虽然有三种重载实现,但是这些方法的内部实现都是一样的。所以我们以第一种举例:

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

有底向上分析

execute(ftask):ftask 能够作为参数,是因为 RunnableFuture 是 Runnable 的子类(Java多态) newTaskFor(task):返回的是 FutureTask(RunnableFuture的实现类),真正调用的构造行数:

public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }

总结

在上面我们说了,FutureTask 是Runnable的子类,所以必然是线程类(存在run()方法)。而且 FutureTask 还存在 private Callable<V> callable 。所以,以FutureTask开启线程的时候,在run()方法的内部继续执行 private Callable<V> callablecall()方法,并且获取其返回值地址。

还有一点

Future<?> submit(Runnable task):点击去发现Executors.callable(runnable, result)

public static <T> Callable<T> callable(Runnable task, T result) {
      if (task == null)
          throw new NullPointerException();
      return new RunnableAdapter<T>(task, result);
}
static final class RunnableAdapter<T> implements Callable<T> {
  final Runnable task;
  final T result;
  RunnableAdapter(Runnable task, T result) {
      this.task = task;
      this.result = result;
  }
  public T call() {
      task.run();
      return result;
  }
}

所以,Runnable作为参数,使用这个适配器既可以转化为Callable了。