官方资料
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的大概内容。