Android Okhttp3 分发器源码解析

在 OkHttp 中,分发器(Dispatcher)是负责调度和执行网络请求的组件。它管理并发请求数量以及请求的优先级,确保合理地使用底层的连接池和线程池,从而提高网络请求的效率性能

默认情况下,OkHttp 使用一个单例的分发器,它可以处理同时进行的最大请求数为 64。也可以通过自定义分发器来修改这些默认设置,以满足特定的需求。


以异步请求为例:

package okhttp3;

final class RealCall implements Call {
  // ...

  @Override public void enqueue(Callback responseCallback) {
    // ...

    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }
  // ...
}

执行了 Call.enqueue() 之后,调用到 Dispatcher.enqueue():


package okhttp3;

public final class Dispatcher {
  private int maxRequests = 64;       // 最大请求数量
  private int maxRequestsPerHost = 5; // 同 Host 下最大请求数量

  private final Deque readyAsyncCalls = new ArrayDeque<>();   // 异步准备队列
  private final Deque runningAsyncCalls = new ArrayDeque<>(); // 异步执行队列
  private final Deque 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);
    }
  }
  // ...
}

可以看到,Dispatcher 定义了三个对列,存放各个状态的任务,方便对各个状态的任务进行管理。调用了 Dispatcher.enqueue() 后会根据当前请求数量来控制任务是否执行,若当前请求数量过多,则先存储在异步等待队列当中。


那存储在等待队列啥时候才能宠幸这里面的任务呢?先来看操作准备队列的方法 Dispatcher.promoteCalls():

package okhttp3;

public final class Dispatcher {
  // ...

  private void promoteCalls() {
    if (runningAsyncCalls.size() >= maxRequests) return; // 是否达到最大请求次数
    if (readyAsyncCalls.isEmpty()) return; // 判断准备队列是否为空

    for (Iterator i = readyAsyncCalls.iterator(); i.hasNext(); ) {
      AsyncCall call = i.next();

      if (runningCallsForHost(call) < maxRequestsPerHost) {
        i.remove();
        runningAsyncCalls.add(call);
        executorService().execute(call); // 线程池执行
      }

      if (runningAsyncCalls.size() >= maxRequests) return; // 是否达到最大请求次数
    }
  }
  // ...
}

这个方法就是查询准备队列是否还有未执行的任务,若有则在线程池中执行


那在异步请求中这个方法什么时候会执行呢?

package okhttp3;

final class RealCall implements Call {

  final class AsyncCall extends NamedRunnable {
    // ...

    @Override protected void execute() {
      try {
        // ...异步请求
      } catch (IOException e) {
        // ...异常处理
      } finally {
        client.dispatcher().finished(this); // 调用
      }
    // ...
  }
}


// Dispatcher

  void finished(AsyncCall call) {
    finished(runningAsyncCalls, call, true);
  }

  private  void finished(Deque calls, T call, boolean promoteCalls) {

      if (promoteCalls) promoteCalls(); // 调用了 promoteCalls()
  }

异步请求后调用了 finished(),最终会去轮询准备队列查看是否还有未执行的任务。这就是异步请求的完整流程。

同步比较简单,直接往同步请求队列加任务,就不展开了


总结:OkHttp 的分发器在网络请求过程中起着非常重要的作用,它有效地管理并发请求、优化请求的顺序和执行,以及管理连接池和线程池,从而提供高效、可靠的网络请求功能。

你可能感兴趣的:(android,okhttp)