为什么java线程池的submit既可以提交runnable也可以提交callable?
前言
大家好,今天鸡翅老哥继续带大家深入了解多线程,我们都知道多线程有两种实现方式,一种是实现runnable接口,一种是实现callable接口。那么线程池的submit提交方式,两种都可以作为参数传递。要知道submit是当需要返回值的情况下才使用,runnable是没有返回值,那么submit为什么可以接收两种呢,我们继续往下看。
submit方法解析
先看下submit的方法,来确定,确实可以提交两种方式。
我们定义一个线程池,来执行两个方法,第一种没有返回值,线程池会自动找到runnable接口,第二种有返回值,线程池会走callable接口的方式。这里大家可以直接点击submit进去,就可以看到具体走的哪个方法。
-
@Test
-
public void test(){
-
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5,5,5, TimeUnit.SECONDS,new LinkedBlockingDeque<>(1024));
-
Future<?> submit = threadPoolExecutor.submit(() -> {
-
System.out.println("submit.runnable.way");
-
});
-
Future<String> submit1 = threadPoolExecutor.submit(() -> {
-
return "submit.callable.way";
-
});
-
}
我们从上面可以发现一个现象。无论是runnable还是callable,返回值都是future。callable我们可以理解,他就是返回一个future。那么runnable是没有返回值的,是怎么转换成future的呢。我们继续看
runnable如何转为future的?
先来看第一段源码
-
public Future<?> submit(Runnable var1) {
-
if (var1 == null) {
-
throw new NullPointerException();
-
} else {
-
RunnableFuture var2 = this.newTaskFor(var1, (Object)null);
-
this.execute(var2);
-
return var2;
-
}
-
}
我们发现runnable传进去后,通过newTaskFor进行了包装,返回了RunnableFuture,RunnableFuture 又继承了runnable和future。futuretask又实现了这个接口,所以自然就可以返回futuretask了。
-
FutureTask<V> implements RunnableFuture<V>
-
public interface RunnableFuture<V> extends Runnable, Future<V> {
-
void run();
-
}
继续深入到newTaskFor,发现他对runnable进行了包装。
-
protected <T> RunnableFuture<T> newTaskFor(Runnable var1, T var2) {
-
return new FutureTask(var1, var2);
-
}
继续跟踪,futuretask的构造参数。发现就是从这一刻开始,你的runnable变为了callable。继续深入到callable方法。
-
public FutureTask(Runnable var1, V var2) {
-
this.callable = Executors.callable(var1, var2);
-
this.state = 0;
-
}
-
public static <T> Callable<T> callable(Runnable var0, T var1) {
-
if (var0 == null) {
-
throw new NullPointerException();
-
} else {
-
return new Executors.RunnableAdapter(var0, var1);
-
}
-
}
这里面有一个RunnableAdapter的适配器。这里我们可以看到RunnableAdapter实现了Callable。这样返回的时候就是Callable,当我们调用RunnableAdapter的call方法的时候,实际调用的就是runnable的run方法。
-
private static final class RunnableAdapter<T> implements Callable<T> {
-
private final Runnable task;
-
private final T result;
-
-
RunnableAdapter(Runnable var1, T var2) {
-
this.task = var1;
-
this.result = var2;
-
}
-
-
public T call() {
-
this.task.run();
-
return this.result;
-
}
-
-
public String toString() {
-
return super.toString() + "[Wrapped task = " + this.task + "]";
-
}
-
}
至此,runnable就转为callable了。
submit提交callable
了解了上面的runnable,再来理解callable就十分简单了。我们看一下他的源码。我们可以看到,直接封装到futuretask。不需要像上面一样进行runnable的转换。
-
public <T> Future<T> submit(Callable<T> var1) {
-
if (var1 == null) {
-
throw new NullPointerException();
-
} else {
-
RunnableFuture var2 = this.newTaskFor(var1);
-
this.execute(var2);
-
return var2;
-
}
-
}
-
protected <T> RunnableFuture<T> newTaskFor(Callable<T> var1) {
-
return new FutureTask(var1);
-
}
-
public FutureTask(Callable<V> var1) {
-
if (var1 == null) {
-
throw new NullPointerException();
-
} else {
-
this.callable = var1;
-
this.state = 0;
-
}
-
}
结尾
文中难免有不足了,欢迎大家讨论!同时有问题,可以找鸡翅老哥交流哦。
文章来源: blog.csdn.net,作者:经典鸡翅,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/hanqing456/article/details/122313490
- 点赞
- 收藏
- 关注作者
评论(0)