1、基本介绍:
- Dispatcher持有一个线程池和三个可代表的线程维护的队列,并提供了add,remove,cancel三个性质的方法。
- 只不过这个取消的方法交给了拦截器RetryAndFollowUpInterceptor处理,拦截器会调用coneation.canel()进行传输层的握手中断。
2、Dispatcher类:
public final class Dispatcher {
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
private Runnable idleCallback;
private ExecutorService executorService;
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
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;
}
...
}
1、在Okhttp中,构建了一个阀值为[0, Integer.MAX_VALUE]的线程池,它不保留任何最小线程数,随时创建更多的线程数,当线程空闲时只能活60秒,它使用了一个不存储元素的阻塞工作队列,一个叫做"OkHttp Dispatcher"的线程工厂。
2、也就是说,在实际运行中,当收到10个并发请求时,线程池会创建十个线程,当工作完成后,线程池会在60s后相继关闭所有线程。
3、同步请求:
synchronized void Dispatcher#executed(RealCall call) {
runningSyncCalls.add(call);
}
4、异步请求:
synchronized void Dispatcher#enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
1、当前请求数小于最大请求数(64),对单一host的请求小于阈值(5):将该任务插入正在执行任务队列,并执行对应任务。
2、如果不满足则将其放入待执行队列。
5、结束任务:
private <T> void Dispatcher#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;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
1、每次调用Call的execute()方法执行完都会调用这个方法。
2、从正在运行的任务队列calls中删除任务call。
3、一般异步任务的promoteCalls会传ture,这时会调用promoteCalls()把readyAsyncCalls中的任务移到runningAsyncCalls中并执行。
4、如果当前整个线程池都空闲下来,执行空闲通知回调线程idleCallback.run( ) 。
6、将等待任务队列添加到运行任务队列:
private void Dispatcher#promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return;
if (readyAsyncCalls.isEmpty()) return;
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
if (runningAsyncCalls.size() >= maxRequests) return;
}
}
1、每次用户重新设置最大maxRequests、maxRequestsPerHost时都会调用。
2、将满足条件的等待任务从readyAsyncCalls删除,添加到runningAsyncCalls并立即执行该任务:遍历待执行任务队列readyAsyncCalls,如果runningAsyncCalls队列call数量小于maxRequests,并且readyAsyncCalls中的等待任务call的host所对应的请求任务数量小于maxRequestsPerHost,则将readyAsyncCalls中的该等待任务call添加到runningAsyncCalls,并调用线程池去执行该call。
7、取消任务:
public synchronized void cancelAll() {
for (AsyncCall call : readyAsyncCalls) {
call.get().cancel();
}
for (AsyncCall call : runningAsyncCalls) {
call.get().cancel();
}
for (RealCall call : runningSyncCalls) {
call.cancel();
}
}
1、取消的方法交给了拦截器RetryAndFollowUpInterceptor处理,拦截器会调用coneation.canel()进行传输层的握手中断。