OkHttp的任务调度
实现同步异步请求
同步:excute()
异步:enqueue()
发送的同步/异步请求都会在dispatcher中管理其状态
作用:维护请求的状态(包括同步和异步)并维护了一个线程池(更高效的执行异步请求),用于执行相应的请求。维护任务队列
通过Call(call本质就是一个Runnable)进行封装,通过dispatcher把执行的请求推到就绪请求队列中。
dispatcher()源码
一个线程池,两个请求队列
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
private Runnable idleCallback;
/** Executes calls. Created lazily. */
private ExecutorService executorService;
/** Ready async calls in the order they'll be run.
就绪状态的异步请求队列
*/
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/** Running asynchronous calls.正在执行的异步请求
Includes canceled calls that haven't finished yet. 已经取消,但是没有执行完的异步请求
*/
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
/** Running synchronous calls. Includes canceled calls that haven't finished yet.*/
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
public Dispatcher(ExecutorService executorService) {
this.executorService = executorService;
}
public Dispatcher() {
}
线程池
//线程池
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;
}
0:核心线程池数量,空闲一段时间之后就会将所有的线程进行销毁
Integer.MAX_VALUE:最大的线程数,任务过来的时候可以无限的扩充线程的最大值,由于受到maxRequests限制,也不是可以无限创建的
60:当线程数大于核心线程数,多余的线程的最大存活时间
比如:开启20个并发请求,就会有20个请求,线程池就会在60s时候相继关闭所有无用的线程。
enqueue
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);//线程池负责自动创建,销毁以及线程的管理
} else {
readyAsyncCalls.add(call);//异步请求加入就绪队列当中,进行缓存等待的操作
}
两个队列
Dispatcher生产者,默认在主线程执行
ExecutorService,消费者池
两个队列一个用于缓存,一个用于执行任务
/** Ready async calls in the order they'll be run.
就绪状态的异步请求队列
*/
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/** Running asynchronous calls.正在执行的异步请求
Includes canceled calls that haven't finished yet. 已经取消,但是没有执行完的异步请求
*/
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
判断最大请求数以及相同主机最大请求数判断,满足的话就可以进入到队列中立即执行,如果不满足,说明执行队列中存满了,就会进入到就绪队列中,等运行队列中有空间了,再把缓存的队列放入到执行队列当中,任务完成之后会调用promoteCall()方法,手动清除缓存区。
缓存请求的异步队列的执行时间
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
if (promoteCalls) promoteCalls();
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
calls.remove():把异步请求从正在执行的异步请求的队列中删除
promoteCalls():调整任务队列的,由于同步和异步都是不安全的,所以他需要在 synchronized中进行。
runningCallsCount():正在执行的异步请求和同步请求的数目总和