OKHttp源码解析(二)线程调度Dispatcher

官方资料

OkHttp官网地址:http://square.github.io/okhttp/
OkHttp GitHub地址:https://github.com/square/okhttp

本篇文章解析一下OKHttp中关于Dispatcher部分的内容。

源码环境

OKHttp3.2.0

1,Dispatcher分析

当我们在使用OKHttp的时候,不管是同步请求还是异步请求,内部都会涉及到一个类Dispatcher,官方给出的注释是:一种策略,当异步请求被执行的时候。然而还是不知道什么意思,我们看看源码就会理解了。

 Policy on when async requests are executed.

Dispatcher它提供了两种默认的构造函数,

 public Dispatcher(ExecutorService executorService) {
    this.executorService = executorService;
  }

  public Dispatcher() {
  }

其中有个参数是ExecutorService,它是线程池,也就是说,Dispatcher的构造可以使用自己定义的线程池ExecutorService。不过它的内部提供了一个默认的线程池的构造

  //默认的线程池创建
  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;
  }

对于其中的参数含义,如下:

1、0:核心线程数量,保持在线程池中的线程数量(即使已经空闲),为0代表线程空闲后不会保留,等待一段时间后停止。
2、Integer.MAX_VALUE:表示线程池可以容纳最大线程数量
3、TimeUnit.SECOND:当线程池中的线程数量大于核心线程时,空闲的线程就会等待60s才会被终止,如果小于,则会立刻停止。
4、new SynchronousQueue():线程等待队列。同步队列,按序排队,先来先服务
5、Util.threadFactory(“OkHttp Dispatcher”, false):线程工厂,直接创建一个名为OkHttp Dispatcher的非守护线程。

接着我们来看下它内部的变量。

 //最大的请求数量为64
 private int maxRequests = 64;
 //每个主机最大请求数量为5
 private int maxRequestsPerHost = 5;

  //线程池
  private ExecutorService executorService;

  //异步请求等待队列,将会有序执行
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

  //正在运行的异步请求队列
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

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

当入队(enqueue)请求时,如果满足(runningRequests<64 && runningRequestsPerHost<5),那么就直接把AsyncCall直接加到runningCalls的队列中,并在线程池中执行。如果runningAsyncCalls队列缓存满了,就放入readyAsyncCalls队列进行缓存等待。

以上的变量便是Dispatcher维护的,主要就是一个线程池以及一些队列,用于缓存执行的call。我们接着分析。

1.1,异步请求

当OKHttp发出异步请求时,即会调用:

client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

            }
        });

其实它的内部在上篇已经提及过,即调用RealCall中的方法enqueue

 void enqueue(Callback responseCallback, boolean forWebSocket) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
  }

即会调用Dispatch中的enqueue方法,将请求call,AsyncCall执行入队操作。

  synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

首先会判断发出的异步请求call是否满足以下条件:

(runningRequests<64 && runningRequestsPerHost<5)

满足时即将请求的call放入到runningAsyncCalls队列中,然后线程池开始执行这个请求。如果不满足的话,则将请求的call放入到等待队列readyAsyncCalls中去。

有线程池中的线程执行call时,我们查看相关的代码可以发现:

executorService().execute(call);

对于其中的call是AsyncCall的对象,我们来了解一下AsyncCall这个类。

1.1.1,AsyncCall

AsyncCall是RealCall的一个内部类,它继承自NamedRunnable,实现了Runnable接口,所以AsyncCall它也会执行execute方法。

 @Override protected void execute() {
      boolean signalledCallback = false;
      try {
        Response response = getResponseWithInterceptorChain(forWebSocket);
        if (canceled) {
          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!
          logger.log(Level.INFO, "Callback failure for " + toLoggableString(), e);
        } else {
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
  }

在excute中,通过getResponseWithInterceptorChain来获取执行请求后返回的结果即response。接着会回调onResponse和onFailure方法,最后回调用dispatch的finished方法。

/** Used by {@code AsyncCall#run} to signal completion. */
  synchronized void finished(AsyncCall call) {
    if (!runningAsyncCalls.remove(call)) throw new AssertionError("AsyncCall wasn't running!");
    promoteCalls();
  }

将该请求call从正在执行的异步队列runningAsyncCalls中移除,然后调用promoteCalls方法继续执行等待队列中的call。

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();
        //将等待队列中的call移动到执行队列中去
      if (runningCallsForHost(call) < maxRequestsPerHost) {
        i.remove();
        runningAsyncCalls.add(call);
        executorService().execute(call);
      }

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

promoteCalls()负责ready的Call到running的Call的转化

具体的执行请求则在RealCall里面实现的,同步的在RealCall的execute里面实现的,而异步的则在AsyncCall的execute里面实现的。里面都是调用RealCall的getResponseWithInterceptorChain的方法来实现责任链的调用。

1.2,同步请求

对于OKHttp发出同步请求时,会执行下面操作:

client.newCall(request).execute();

即直接将一个请求call放入到Deque中去,然后由Realcall来真正的执行。

@Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    try {
      client.dispatcher().executed(this);
      Response result = getResponseWithInterceptorChain(false);
      if (result == null) throw new IOException("Canceled");
      return result;
    } finally {
      client.dispatcher().finished(this);
    }
  }

同步流程基本跟异步一致,可以认为是异步中的某一个执行call的流程。以上便是Dispatcher的大概内容。

阅读更多
版权声明:本文为博主原创文章,转载请注明出处,联系作者:QQ:275137657 https://blog.csdn.net/lj188266/article/details/79268184
文章标签: 源码 okhttp3
上一篇http学习记录
下一篇类加载器classloader-java简析
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭