OkHttp3源码解析--Call同步请求

前面创建了Call对象,接下来就是执行。执行又分为了同步执行和异步执行,先看同步执行过程。

还是之前的过程:

//步骤1:创建OkHttpClient对象
OkHttpClient client = new OkHttpClient.Builder()
  .readTimeout(5, TimeUnit.SECONDS)
  .build();
//步骤2:创建Request对象
Request request = new Request.Builder()
    .url("http://www.baidu.com")
    .get()
    .build();
//步骤3:创建Call对象
Call call = client.newCall(request);
//步骤4:进行请求
//异步请求方式
call.enqueue(new Callback() {
  @Override
  public void onFailure(Call call, IOException e) {
    System.out.println("Fail");
  }
  @Override
  public void onResponse(Call call, Response response) throws IOException {
    System.out.println(response.body().string());
  }
});
//同步请求方式
Response response = call.execute();

通过Call对象的execute方法来完成同步请求,这个方法会一直阻塞至请求结果返回,或者请求过程出现错误。

同步请求–NewCall#execute方法的实现

@Override public Response execute() throws IOException {
    synchronized (this) {//锁住这个Call对象
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;//看是否执行过,每一个Call只能执行一次
    }
    captureCallStackTrace();
    eventListener.callStart(this);//回调请求执行事件监听器
    try {
      client.dispatcher().executed(this);//加入到Dispatcher对象的runningSyncCalls同步任务队列中
      Response result = getResponseWithInterceptorChain();//阻塞,执行一系列拦截器,完成请求,返回结果
      if (result == null) throw new IOException("Canceled");//返回结果为null的话,就是这个请求在后续的处理过程中被取消了。
      return result;//返回结果
    } catch (IOException e) {
      eventListener.callFailed(this, e);//事件监听回调
      throw e;
    } finally {
      client.dispatcher().finished(this);//完成当前请求,将任务从同步任务队列中删除。
    }
  }

过程简述:

  • 判断是否已经能执行过,如果已经执行过,直接抛异常,停止请求;

  • 回调事件监听callStart;

  • 调用Dispatcher的executed方法,将任务添加到同步任务队列中;

  • 阻塞,调用getResponseWithInterceptorChain方法,执行拦截器链,完成请求,返回结果

  • 判断请求结果,看是否请求被取消了;

  • 再次调用Dispatcher中的finished方法,将当前Call从同步任务队列中删除,当前请求Call完成。

这个过程中有Dispatcher的参与,看一下它的相关代码:

Dispatcher

public final class Dispatcher {
  private int maxRequests = 64;//最大请求数量,包括同步请求和异步请求,从下面的三种队列中相加进行统计
  private int maxRequestsPerHost = 5;//访问同一个主机的请求最大数量
  private @Nullable Runnable idleCallback;//空闲时回调,空闲指的时正在执行同步和异步的Call个数为0的时候/** 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<>();//准备被执行的异步Call-->AsyncCall
  /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();//正在执行的异步Call-->AsyncCall
  /** Running synchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();//正在执行的同步Call-->RealCallpublic Dispatcher(ExecutorService executorService) {
    this.executorService = executorService;
  }public Dispatcher() {
  }
  //创建线程池
  public synchronized ExecutorService executorService() {
    if (executorService == null) {
      //线程池中核心线程为0,最大线程数可以为Integer.MAX_VALUE,空闲存活时间为60S
      //即这个线程池的特点是,来一个请求可以创建一个新的线程。但是线程数也有限制,上面的maxRequests可以限制最大的线程数量不能超过64.
      //响应速度快。
      //空闲60S后会回收所有线程的资源,也可以节省资源。
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }
  //Realcall中的client.dispatcher().executed(this);执行到这
  /** Used by {@code Call#execute} to signal it is in-flight. */
  synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);//将Call直接添加到同步任务队列中
  }/** Used by {@code AsyncCall#run} to signal completion. */
  void finished(AsyncCall call) {
    finished(runningAsyncCalls, call, true);
  }/** Used by {@code Call#execute} to signal completion. */
  void finished(RealCall call) {
    //第三个参数promoteCalls:同步请求时为false,异步为true。
    finished(runningSyncCalls, call, false);
  }//calls异步和同步对应的任务队列
  //call 正在进行的call
  //promoteCalls 同步请求是为false   异步请求时为true
  private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
    int runningCallsCount;//正在执行的Call的数量
    Runnable idleCallback;//空闲回调
    synchronized (this) {
      //删除当前Call
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
      if (promoteCalls) promoteCalls();//同步请求不执行,异步请求执行
      runningCallsCount = runningCallsCount();//统计正在执行的Call的数量,包括同步请求个异步请求;
      idleCallback = this.idleCallback;
    }if (runningCallsCount == 0 && idleCallback != null) {
      idleCallback.run();
    }
  }}

可以看到,在同步请求的时候:

首先调用executed(RealCall call)方法,将RealCall对象添加到runningSyncCalls队列中;

其实也就是添加到队列中,后续对请求的执行,不会从同步队列中获取任务,而是直接对上述的RealCall进行操作。这里的队列其实就是为了多个任务的进度控制。

然后,任务执行完之后,执行finished方法,将当前任务从队列中删除。就可以了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值