Okhttp学习笔记(二)核心之一:Dispatcher

学习资料:

BAT大牛带你深度剖析Android 十大开源框架

上一篇文章:
Okhttp学习笔记(一) 初步认识&& 源码浅析

Dispatcher类分析

  • 发送的同步、异步请求由Dispatcher管理状态
  • 作用:维护同步和异步的请求状态,维护一个线程池,用于执行请求

成员变量

  // 最大请求数
  private int maxRequests = 64;
  // 相同主机最大请求数
  private int maxRequestsPerHost = 5;
  private @Nullable Runnable idleCallback;

  // 重要 维护的线程池
  private @Nullable ExecutorService executorService;
  
  // 准备状态中的异步请求队列
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

  // 执行中的异步请求队列(包含已经取消但是还没取消的请求)
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

  // 同步请求队列
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

创建线程池

核心线程池设置为0,最大线程数设置为Integer的最大值,但是实际上受到maxRequests的限制,并且在空闲60s会自动回收线程;

 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的executed方法

直接加入队列

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

Dispatcher的enqueue方法

 synchronized void enqueue(AsyncCall call) {
     // 判断请求数是佛满足要求
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
    // 加入运行队列并且使用线程池执行
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
    // 加入就绪队列
      readyAsyncCalls.add(call);
    }
  }

在哪调用了?

以异步请求为例,在实际使用中,我们是通过OkHttpClient的newCall()方法调用的enqueue方法,在Okhttp学习笔记(一)提到过,实际执行的是RealCall类的enqueue方法

  // realCall类里调用的dispatcher对象的 enqueue 方法
  client.dispatcher().enqueue(new AsyncCall(responseCallback)); 

AsyncCall是一个包装了Callback的Runnable,是RealCall类的内部类,最终线程池会执行AsyncCall的execute方法,通过 getResponseWithInterceptorChain()方法执行请求获得请求结果,并且回调相应的结果,并且会通过RealCall持有的client客户端对象,最终调用Dispatcher的finished方法

 final class AsyncCall extends NamedRunnable {

    ...
    @Override protected void execute() {
      boolean signalledCallback = false;
      try {
      // 获取拦截器链 获取response
        Response response = getResponseWithInterceptorChain();
        // 判断是否取消
        if (retryAndFollowUpInterceptor.isCanceled()) {
          signalledCallback = true;
          // 取消则回调onFailure
          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
        } else {
          signalledCallback = true;
          // 没取消则回调onResponse
          responseCallback.onResponse(RealCall.this, response);
        }
      } catch (IOException e) {
        if (signalledCallback) {
          // Do not signal the callback twice!
          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
        } else {
          // 捕获到异常 回调到onFailure方法
          eventListener.callFailed(RealCall.this, e);
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        // 调用finished方法
        client.dispatcher().finished(this);
      }
    }
    ...
 }

Dispatcher的finished方法

通过回调后最终会走到以下方法:

  private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
    int runningCallsCount;
    Runnable idleCallback;
    synchronized (this) {
      // 移除请求
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
      if (promoteCalls) promoteCalls(); // 异步会调用的方法
      runningCallsCount = runningCallsCount(); // 获取正在执行的请求数
      idleCallback = this.idleCallback;
    }
     // 执行数为0时,且idleCallback 不为空,执行idleCallback.run();
    if (runningCallsCount == 0 && idleCallback != null) {
      idleCallback.run();
    }
  }

除了移除请求,重点看一下异步会执行的promoteCalls方法:

 private void promoteCalls() {
    // 判断是否超过最大请求数,如果超过了就直接结束
    if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
    // 判断是否有就绪的队列,没有则返回
    if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.

    // 遍历就绪等待队列
    for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
      AsyncCall call = i.next();

    // 如果满足最大同时请求主机数,从就绪队列移除,并添加到运行队列,然后执行请求
      if (runningCallsForHost(call) < maxRequestsPerHost) {
        i.remove();
        runningAsyncCalls.add(call);
        executorService().execute(call); // 最终会执行AsyncCall的execute方法,见上面
      }

      if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
    }
  }

总结:

  1. Dispatcher是一个调度器,在创建OkHttpClient自动创建;
  2. 默认最大请求数为64;
  3. 默认最大相同主机请求数为5;
  4. 同步请求: (在RealCall中)在请求前调用dispatcher加入请求队列,然后直接获取结果;
  5. 异步请求:在RealCall调用dispatcher的enqueue方法,在dispatcher的enqueue方法方法中判断加入请求队列或者加入等待队列,最终执行AsyncCall 的execute方法,获取请求结果并回调
  6. 请求完成:会调用Dispatcher的finished方法,移除请求,调整请求数,如果是异步请求的话还会调用promoteCalls方法来调用下一个请求
  7. 异步请求完成:promoteCalls方法中会判断是否满足两个条件(最大请求数和相同主机数),如果满足的话会按队列调用下一个请求
发布了27 篇原创文章 · 获赞 6 · 访问量 1653

猜你喜欢

转载自blog.csdn.net/weixin_41802023/article/details/102859848