关于线程池,写过两篇文章《线程池基本原理详解》、《定时类线程池工作原理》。
这两篇文章,从源码的角度,分析的很详细,文章也很长。
这一篇,介绍一个很小的点,使用线程池时,任务提交的方法,
execute 和 submit 这两个到底怎么选?
一、示例代码
先说 Runnable任务,可以这么写
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("test runnable");
}
};
JAVA8 之后可以这么写
Runnable runnable2 = () -> {
System.out.println("test runnable2");
};
同样的Callable 任务,可以这么写
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return 1 + 1;
}
};
Callable<Integer> callable1 = () -> {
return 1 + 1;
};
言归正传,写个示例代码
public static void main(String[] args) throws Exception {
ExecutorService pool = Executors.newFixedThreadPool(2);
Future<Integer> future = pool.submit(() -> {
return 1 + 1;
});
pool.execute(() -> {
System.out.println("test runnable2");
});
pool.shutdown();
}
直观的说,submit
是有返回值的, execute
没有返回值
二、submit 源码
submit
的顶层接口在 ExecutorService
中定义的
<T> Future<T> submit(Callable<T> task);
在抽象类 AbstractExecutorService
中,实现了 submit
方法
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
这个方法很简洁,submit 方法,将任务包装成 FutureTask 对象 ,传入 execute 方法,最终将 任务对象返回(可获取任务执行的结果)。
void execute(Runnable command);
execute
方法,在ThreadPoolExecutor
中实现,在《线程池基本原理详解》中,有详细讲解,这里不展开说了。
从代码层面,两者的区别很明显。
submit 方法和 execute 功能差不多,都是提交任务。不同的是,submit 包装了任务后,才调用execute,并返回了任务本身(可获取任务执行结果)。
三、总结
线程池提交任务,有 execute 和 submit 两种方法,差别不大。
execute 没有返回值,仅处理 Runnable 任务。
submit 有返回值, Runnable 、Callable 任务都能处理。
至于 Runnable 任务和 Callable 任务有什么区别,本篇就不说了。