【OkHttp】OkHttp 源码分析 ( 同步 / 异步 Request 请求执行原理分析 )(二)

简介: 【OkHttp】OkHttp 源码分析 ( 同步 / 异步 Request 请求执行原理分析 )(二)

二、OkHttp 异步 Request 请求源码分析


异步 Request 请求涉及到线程调度 , 比较复杂 ;


OKHttpClient 调用 newCall 获取 RealCall , 然后调用 RealCall 的 enqueue 方法进行异步 Get/Post 请求 , 在该方法中最终调用 OKHttpClient 对象中的 Dispatcher dispatcher 线程调度器 的 enqueue 方法 , 进行异步请求 ;



1、Dispatcher 调度器 enqueue 方法分析


在 Dispatcher 的 enqueue 方法中 , 调用了 findExistingCallWithHost 方法获取 AsyncCall , 然后在方法最后调用了 promoteAndExecute 进行后续执行异步任务操作 ;


/**
 * Policy on when async requests are executed.
 *
 * <p>Each dispatcher uses an {@link ExecutorService} to run calls internally. If you supply your
 * own executor, it should be able to run {@linkplain #getMaxRequests the configured maximum} number
 * of calls concurrently.
 */
public final class Dispatcher {
  void enqueue(AsyncCall call) {
    synchronized (this) {
      readyAsyncCalls.add(call);
      // Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
      // the same host.
      if (!call.get().forWebSocket) {
        AsyncCall existingCall = findExistingCallWithHost(call.host());
        if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
      }
    }
    promoteAndExecute();
  }
  @Nullable private AsyncCall findExistingCallWithHost(String host) {
    for (AsyncCall existingCall : runningAsyncCalls) {
      if (existingCall.host().equals(host)) return existingCall;
    }
    for (AsyncCall existingCall : readyAsyncCalls) {
      if (existingCall.host().equals(host)) return existingCall;
    }
    return null;
  }
}


AsyncCall 继承了 NamedRunnable , NamedRunnable 实现了 Runnable 接口 , AsyncCall 本质是 Runnable ;

final class AsyncCall extends NamedRunnable
public abstract class NamedRunnable implements Runnable



2、Dispatcher 调度器 promoteAndExecute 方法分析


分析 promoteAndExecute 方法 : 将符合条件的调用从 readyAsyncCalls 提升为 runningAsyncCalls , 并且在线程池中调用它们 ; 这些操作必须同步调用 , 因为执行这些调用需要调用用户代码 ;


最终的异步请求执行调用的是 AsyncCall 的 executeOn 方法 ;


 

AsyncCall asyncCall = executableCalls.get(i);
      asyncCall.executeOn(executorService());


Dispatcher | promoteAndExecute 方法源码 :


 

/**
   * Promotes eligible calls from {@link #readyAsyncCalls} to {@link #runningAsyncCalls} and runs
   * them on the executor service. Must not be called with synchronization because executing calls
   * can call into user code.
   *
   * @return true if the dispatcher is currently running calls.
   */
  private boolean promoteAndExecute() {
    assert (!Thread.holdsLock(this));
    List<AsyncCall> executableCalls = new ArrayList<>();
    boolean isRunning;
    synchronized (this) {
      for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
        AsyncCall asyncCall = i.next();
        if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
        if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.
        i.remove();
        asyncCall.callsPerHost().incrementAndGet();
        executableCalls.add(asyncCall);
        runningAsyncCalls.add(asyncCall);
      }
      isRunning = runningCallsCount() > 0;
    }
    for (int i = 0, size = executableCalls.size(); i < size; i++) {
      AsyncCall asyncCall = executableCalls.get(i);
      asyncCall.executeOn(executorService());
    }
    return isRunning;
  }




3、AsyncCall 的 executeOn 方法分析


AsyncCall 的 executeOn 方法中 , 主要使用了 传入的 ExecutorService executorService 线程池 , 执行异步请求任务 ;


RealCall $ AsyncCall | executeOn 方法代码 :


final class RealCall implements Call {
  final class AsyncCall extends NamedRunnable {
    /**
     * Attempt to enqueue this async call on {@code executorService}. This will attempt to clean up
     * if the executor has been shut down by reporting the call as failed.
     */
    void executeOn(ExecutorService executorService) {
      assert (!Thread.holdsLock(client.dispatcher()));
      boolean success = false;
      try {
        executorService.execute(this);
        success = true;
      } catch (RejectedExecutionException e) {
        InterruptedIOException ioException = new InterruptedIOException("executor rejected");
        ioException.initCause(e);
        transmitter.noMoreExchanges(ioException);
        responseCallback.onFailure(RealCall.this, ioException);
      } finally {
        if (!success) {
          client.dispatcher().finished(this); // This call is no longer running!
        }
      }
    }
  }
}






三、OkHttp 请求时序图参考


image.png




目录
相关文章
|
Android开发
【OkHttp】OkHttp Get 和 Post 请求 ( 同步 Get 请求 | 异步 Get 请求 | 同步 Post 请求 | 异步 Post 请求 )(一)
【OkHttp】OkHttp Get 和 Post 请求 ( 同步 Get 请求 | 异步 Get 请求 | 同步 Post 请求 | 异步 Post 请求 )(一)
1080 0
|
缓存 Java Spring
异步编程 - 09 Spring框架中的异步执行_@Async注解异步执行原理&源码解析
异步编程 - 09 Spring框架中的异步执行_@Async注解异步执行原理&源码解析
52 0
|
5月前
|
Java Spring
SpringBoot+async异步调用接口以及几个任务同时完成和异步接口实现和调用
SpringBoot+async异步调用接口以及几个任务同时完成和异步接口实现和调用
126 0
|
设计模式 缓存 监控
OKHttp3 从使用到原理分析
Okhttp3 是我们经常使用的一个网络框架,可扩展性强,支持 get 缓存, spdy、http2.0,gzip 压缩减少数据流量,同步和异步请求,连接池复用机制等特性让广大 android 开发者深爱不已,今天我就带大家从 Okhttp 简单使用,到各种好用拦截器原理了解 Okhttp3
1775 0
OKHttp3 从使用到原理分析
|
存储
Retrofit+OkHttp实现Cookie持久化,RxJava方式
Retrofit+OkHttp实现Cookie持久化,RxJava方式
306 0
|
调度
【OkHttp】OkHttp 源码分析 ( 同步 / 异步 Request 请求执行原理分析 )(一)
【OkHttp】OkHttp 源码分析 ( 同步 / 异步 Request 请求执行原理分析 )(一)
293 0
【OkHttp】OkHttp Get 和 Post 请求 ( 同步 Get 请求 | 异步 Get 请求 | 同步 Post 请求 | 异步 Post 请求 )(二)
【OkHttp】OkHttp Get 和 Post 请求 ( 同步 Get 请求 | 异步 Get 请求 | 同步 Post 请求 | 异步 Post 请求 )(二)
345 0
|
Java
OkHttp3源码解析(一)之请求流程
带你从源码理解OkHttp3的原理
2737 0
|
Java
OkHttp 3.7源码分析(二)——拦截器&一个实际网络请求的实现
前一篇博客中我们介绍了OkHttp的总体架构,接下来我们以一个具体的网络请求来讲述OkHttp进行网络访问的具体过程。由于该部分与OkHttp的拦截器概念紧密联系在一起,所以将这两部分放在一起进行讲解。
13400 0
|
Java 调度 安全
OkHttp3源码详解(六)Okhttp任务队列工作原理
阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680 1 概述 1.1 引言 android完成非阻塞式的异步请求的时候都是通过启动子线程的方式来解决,子线程执行完任务的之后通过handler的方式来和主线程来完成通信。