okHttp面试题 ---- 调度器dispatcher

okHttp面试题 ---- 调度器dispatcher

讲完了主要的网络请求部分,再来看一下okhttp的另外一个组成部分、调度器dispatcher
还是这副简陋又直观的viso流程图 可以看到,在生成realcall之后,到拦截器网络请求之前,线程的分配及开启工作是由dispatcher来完成的,相信即使大家不看源码也清楚这个类是做什么工作的

在这里插入图片描述所以接下来就我看一下调度器的重要组成部分

队列

 private int maxRequests = 64;
 //  最大请求为64
  private int maxRequestsPerHost = 5;
 //  每个host最大请求为5
  private @Nullable Runnable idleCallback;

  /** Executes calls. Created lazily. */
  private @Nullable ExecutorService executorService;
  // 线程池

  /** Ready async calls in the order they'll be run. */
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
  //  异步等待队列

  /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
  //  异步执行队列

  /** Running synchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
  //  同步执行队列

上面这些就是比较重要的几个对象和容器,主要是有三个队列其用处就和他的名字一样,不再赘述

方法

//  异步
 synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

// 同步
synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
  }

上面是我们常用的两种启动方式
enqueue方法中,先判断其大小以及当前执行队列是否以满,判断后选择加入到准备队列或是执行队列
executed同步方法则直接加入到同步执行队列,毕竟就这么一个队列

其实调度器这边没有太多可讲的东西,看就完事了

 public synchronized ExecutorService executorService() {
    if (executorService == null) {
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }

dispatcher本身是一个单例模式,此方法即是创建线程池的方法,线程锁+判空,调用时机是在第一次开线程发起请求的时候被调用

 public synchronized void setIdleCallback(@Nullable Runnable idleCallback) {
    this.idleCallback = idleCallback;
  }//设置回调接口

 public synchronized void setMaxRequestsPerHost(int maxRequestsPerHost) {
    if (maxRequestsPerHost < 1) {
      throw new IllegalArgumentException("max < 1: " + maxRequestsPerHost);
    }
    this.maxRequestsPerHost = maxRequestsPerHost;
    promoteCalls();
  }//设置单一host最大请求数
  
public synchronized void cancelAll() {
    for (AsyncCall call : readyAsyncCalls) {
      call.get().cancel();
    }

    for (AsyncCall call : runningAsyncCalls) {
      call.get().cancel();
    }

    for (RealCall call : runningSyncCalls) {
      call.cancel();
    }
  }//取消全部任务

都是一些配置线程池信息的方法,包括重载了三次的finished方法分别处理三个队列等等,代码全都拿上来会显得很烦多,这里只展示了这么两三个方法,如果感兴趣的话可以自行翻阅一下源码,整个dispatcher内也不过是两百来行代码,抽出几分钟就能看懂,别偷懒啊我看见你了,鼠标怎么往屏幕右上角移动了,懒是原罪嗷
在这里插入图片描述
关于调度器在有人问题的时候我们只需要回答出这些关键点就可以了,代表你确实看过,确实懂,至于每一个方法细节是如何去实现的,大部分有几年经验的程序员都可以自己写出来,坦白来说okhttp的线程池调度器算不得特别的厉害,但也不差,是考虑到各种各样的因素,总和下来这样的一个dispatcher更契合更广泛,如果你有研究调度器每一个方法的时间,倒不如把这些时间用在cache类或者httpcodec之类的关键类上,这些更能有助于你整体的去理解okhttp

=============================================================================
题外话,最近我被人嘲讽了,我在写okhttp的时候他也有看到,并且问我为什么不用dio,我一脸懵逼,dio是什么网络请求框架,然后我简单的搜索了一下,现在他已经半残了,flutter不得不说还是要找时间也学一下的,谷歌爸爸这两年来感觉了,kotlin还没推上去,flutter又开始上了,小程序,h5混合,包括RN都在冲击着原生android市场,不过要相信,好的android是永远不会被取代的,但是这几个方向多少都得学学,别问,问就真香
在这里插入图片描述

interesting!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值