美文网首页Android技术知识Android开发
OkHttp源码之同步、异步的区别

OkHttp源码之同步、异步的区别

作者: 低情商的大仙 | 来源:发表于2018-09-18 22:52 被阅读5次

对于okhttp来说,大家都知道有同步和异步两种模式,所谓同步就是在发起请求的线程完成整个网络的连接传输过程,异步是新建一个线程完成这些流程,那么不知大家有没有想过,异步是不是就新的线程中直接调用同步的请求方法实现的呢?
我们今天就来探讨这个问题。
首先,我们看下同步请求方法:

@Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    //初始化异常扑捉器
    captureCallStackTrace();
    //进度监听
    eventListener.callStart(this);
    try {
    //只是简单的加入到了dispatcher的同步请求队列,没有任何作用
      client.dispatcher().executed(this);
      //真正获取请求结果
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } catch (IOException e) {
      eventListener.callFailed(this, e);
      throw e;
    } finally {
    //将自己从dispatcher的同步队列中移除
      client.dispatcher().finished(this);
    }
  }

上面的注释将每一步的作用都说的很清楚,核心就是那句getResponseWithInterceptorChain();这里是获取真正结果的。
那么异步的是怎么样的呢?

@Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

这里我们看到这里核心就是封装了一个AsyncCall中,塞到了线程调度器中,真正的请求是在线程调度器中执行的,我们看下线程调度器中的相关代码:

 synchronized void enqueue(AsyncCall call) {
        //省略不相干代码
      executorService().execute(call);
      //省略不相干代码
   
  }

可以看到,真正的异步请求是通过封装的AsyncCall来执行的,而且是通过一个线程池执行的,那么我们可以大胆猜测AsyncCall肯定有一个run()方法,核心请求在那里。
我们继续看AsyncCall:

final class AsyncCall extends NamedRunnable {

可以看到,继承了NamedRunnable,继续跟进去:

public abstract class NamedRunnable implements Runnable {
  protected final String name;

  public NamedRunnable(String format, Object... args) {
    this.name = Util.format(format, args);
  }

  @Override public final void run() {
    String oldName = Thread.currentThread().getName();
    Thread.currentThread().setName(name);
    try {
      execute();
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }

  protected abstract void execute();
}

整个NamedRunnable非常简单,主要就是为了给线程设置名字而已,我们重点关注的是在run()方法中调用了execute()方法,所以,AsyncCall的核心方法在execute()中:

@Override protected void execute() {
      boolean signalledCallback = false;
      try {
      //核心的获取真正的网络请求结果
        Response response = getResponseWithInterceptorChain();
        //判断该请求是否被取消,取消了返回失败,没有取消正常回调
        if (retryAndFollowUpInterceptor.isCanceled()) {
          signalledCallback = true;
          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
        } else {
          signalledCallback = true;
          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 {
          eventListener.callFailed(RealCall.this, e);
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }

可以看到这里并没有直接调用RealCall的同步请求方法execute(),而是类似的代码又写了一遍,这是为什么呢?我们来对比下两个方法有什么不一样
先看同步:

  • 修改标记位
  • 初始化异常捕捉器
  • 进度监听器回调
  • 获取请求结果

再看异步:

  • 获取请求结果
  • 判断请求是否结束,回调结果

差异很明显,我们现在要分析的是造成这些差别的原因,首先是同步请求中有的:修改标记位、初始化异常扑捉器、进度监听器回调
这个其实没有在AsyncCall中执行,而是在RealCall的enqueue()方法中执行的:

 @Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

也就是说这三点其实并没有核心区别,只是在不同的地方调用了而已,那么真正的区别就是异步请求多了一个:判断请求是否结束,然后回调。
其实仔细想想,也不难理解,对于同步请求来说,这个请求只在当前线程进行,没有其他线程操作这个请求,那么请求结束后也不存在被取消的情况,然而异步请求不一样,在子线程请求的过程中,这个请求有可能在其他线程被取消了,所以加了这样的判断是非常合理的。

总结

其实没什么好总结的,之所以异步请求没有直接调用同步请求方法就是因为异步多了一个判断而已,done!

相关文章

  • OkHttp源码之同步、异步的区别

    对于okhttp来说,大家都知道有同步和异步两种模式,所谓同步就是在发起请求的线程完成整个网络的连接传输过程,异步...

  • 简述OkHttp3.0

    本文主要以源码形式解读OkHttp内部实现,源码基于okhttp:3.10.0。 同步请求 异步请求的例子 先看一...

  • OkHttp详解

    OkHttp用法 同步和 异步请求 源码解析 Interceptor 是okHttp最核心的东西 网络请求 缓存,...

  • Android知名三方库OKHttp(一) - 基本使用源码分析

    本文目标 搞明白OKHttp的源码同步请求和异步请求基本流程 基本使用 同步请求 异步请求 1.创建okHttpC...

  • OkHttp 异步请求

    在上两篇文章中介绍了OkHttp同步请求以及同步请求的源码分析,其中也提到了OkHttp的同步请求和异步请求的前三...

  • Okhttp3源码分析(3) Interceptor拦截器

    okhttp3源码分析基于okhttp3.10.0。 在前面章节里提到过,okhttp不管是同步请求还是异步请求,...

  • Android okHttp网络请求之Get/Post请求

    Android okHttp网络请求之Get/Post请求 异步同步

  • OkHttp源码解析 -- 同步异步处理

    前言: 使用OkHttp,执行网络请求时会有异步还是同步处理。先说下异步和同步的区别,同步并不是指在UI线程中执行...

  • ok小知识点

    1.OKHttp同步和异步的区别 同步:execute()方法 请求网络数据要在子线程中完成操作,然后...

  • 高级知识点

    1.OKHttp同步和异步的区别 同步:execute()方法 请求网络数据要在子线程中完成操作,然后...

网友评论

    本文标题:OkHttp源码之同步、异步的区别

    本文链接:https://www.haomeiwen.com/subject/csnvnftx.html