为什么java线程池的submit既可以提交runnable也可以提交callable?

举报
经典鸡翅 发表于 2022/02/18 00:43:30 2022/02/18
1.8k+ 0 0
【摘要】 前言 大家好,今天鸡翅老哥继续带大家深入了解多线程,我们都知道多线程有两种实现方式,一种是实现runnable接口,一种是实现callable接口。那么线程池的submit提交方式,两种都可以作为参数传递。要知道submit是当需要返回值的情况下才使用,runnable是没有返回值,那么submit为什么可以接收两种呢,我们继续往下看...

前言

大家好,今天鸡翅老哥继续带大家深入了解多线程,我们都知道多线程有两种实现方式,一种是实现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

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

作者其他文章

评论(0

抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。