2.1 请求执行入口分析
2.1.1 同步请求入口:RealCall.execute()
// 源码路径: okhttp3/RealCall.java
public Response execute() throws IOException {
synchronized (this) {
// 检查是否已经执行
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
// 超时计时开始
transmitter.timeoutEnter();
// 触发事件监听器(如果设置)
transmitter.callStart();
try {
// 将当前请求加入Dispatcher的同步执行队列
client.dispatcher().executed(this);
// 通过拦截器链获取响应
return getResponseWithInterceptorChain();
} finally {
// 无论成功或失败,最终通知Dispatcher请求完成
client.dispatcher().finished(this);
}
}
2.1.2 异步请求入口:RealCall.enqueue()
// 源码路径: okhttp3/RealCall.java
public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
// 触发事件监听器
transmitter.callStart();
// 使用Dispatcher调度异步请求
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
2.2 Dispatcher调度器详解
2.2.1 Dispatcher核心数据结构
// 源码路径: okhttp3/Dispatcher.java
public final class 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<>();
}
2.2.2 线程池创建过程
// 源码路径: okhttp3/Dispatcher.java
public synchronized ExecutorService executorService() {
if (executorService == null) {
// 创建线程池
executorService = new ThreadPoolExecutor(
0, // 核心线程数
Integer.MAX_VALUE, // 最大线程数
60, // 空闲线程存活时间(秒)
TimeUnit.SECONDS,
new SynchronousQueue<>(), // 无容量阻塞队列
Util.threadFactory("OkHttp Dispatcher", false) // 线程工厂
);
}
return executorService;
}
线程池特点:
- 无核心线程,最大线程数无限
- 空闲线程60秒后回收
- 使用SynchronousQueue(每个任务必须有可用线程立即处理)
- 适合大量短生命周期的异步任务
2.2.3 异步请求入队流程
2.2.4 异步请求执行源码
// 源码路径: okhttp3/Dispatcher.java
void enqueue(AsyncCall call) {
synchronized (this) {
// 将请求加入准备队列
readyAsyncCalls.add(call);
}
// 尝试执行请求
promoteAndExecute();
}
private boolean promoteAndExecute() {
List<AsyncCall> executableCalls = new ArrayList<>();
synchronized (this) {
// 遍历准备队列
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
// 检查是否超过最大请求数
if (runningAsyncCalls.size() >= maxRequests) break;
// 检查是否超过主机最大请求数
if (runningCallsForHost(call) >= maxRequestsPerHost) continue;
// 从准备队列移除
i.remove();
// 加入可执行列表
executableCalls.add(call);
// 加入运行队列
runningAsyncCalls.add(call);
}
}
// 执行符合条件的请求
for (AsyncCall call : executableCalls) {
call.executeOn(executorService());
}
return !executableCalls.isEmpty();
}
2.3 异步请求执行过程
2.3.1 AsyncCall执行流程
// 源码路径: okhttp3/RealCall.AsyncCall
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
this.responseCallback = responseCallback;
}
@Override protected void execute() {
try {
// 通过拦截器链获取响应
Response response = getResponseWithInterceptorChain();
// 回调成功结果
responseCallback.onResponse(RealCall.this, response);
} catch (IOException e) {
// 回调失败结果
responseCallback.onFailure(RealCall.this, e);
} finally {
// 结束请求
client.dispatcher().finished(this);
}
}
}
2.3.2 请求完成处理
// 源码路径: okhttp3/Dispatcher.java
void finished(AsyncCall call) {
// 1. 从运行队列移除
synchronized (this) {
if (!runningAsyncCalls.remove(call))
throw new AssertionError("AsyncCall wasn't running!");
}
// 2. 重新调度等待请求
promoteAndExecute();
}
2.4 同步请求执行过程
2.4.1 同步请求入队
// 源码路径: okhttp3/Dispatcher.java
synchronized void executed(RealCall call) {
// 将请求加入同步运行队列
runningSyncCalls.add(call);
}
2.4.2 同步请求完成
// 源码路径: okhttp3/Dispatcher.java
void finished(RealCall call) {
synchronized (this) {
// 从同步运行队列移除
if (!runningSyncCalls.remove(call))
throw new AssertionError("Call wasn't in-flight!");
}
}
2.5 请求取消机制
2.5.1 取消单个请求
// 源码路径: okhttp3/RealCall.java
public void cancel() {
// 1. 标记为已取消
transmitter.cancel();
// 2. 中断连接(如果已建立)
if (connection != null) {
connection.cancel();
}
}
2.5.2 批量取消请求
// 源码路径: okhttp3/Dispatcher.java
public void cancelAll() {
// 取消所有等待的异步请求
for (AsyncCall call : readyAsyncCalls) {
call.get().cancel();
}
// 取消所有正在运行的异步请求
for (AsyncCall call : runningAsyncCalls) {
call.get().cancel();
}
// 取消所有同步请求
for (RealCall call : runningSyncCalls) {
call.cancel();
}
}
2.6 调度策略调优
2.6.1 调整并发参数
// 设置全局最大并发请求数
dispatcher.setMaxRequests(128);
// 设置每个主机最大并发数
dispatcher.setMaxRequestsPerHost(10);
// 应用到OkHttpClient
OkHttpClient client = new OkHttpClient.Builder()
.dispatcher(dispatcher)
.build();
2.6.2 自定义线程池
// 创建自定义线程池
ExecutorService customExecutor = new ThreadPoolExecutor(
4, // 核心线程数
64, // 最大线程数
30, // 空闲时间(秒)
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(256), // 有界队列
new ThreadFactory() {
private int count = 0;
@Override public Thread newThread(Runnable r) {
return new Thread(r, "CustomOkHttp-" + count++);
}
}
);
// 设置到Dispatcher
Dispatcher dispatcher = new Dispatcher();
dispatcher.setExecutorService(customExecutor);
// 应用到OkHttpClient
OkHttpClient client = new OkHttpClient.Builder()
.dispatcher(dispatcher)
.build();
2.7 请求队列监控
2.7.1 获取队列状态
Dispatcher dispatcher = client.dispatcher();
// 获取正在运行的异步请求数
int runningAsyncCount = dispatcher.runningCallsCount();
// 获取等待的异步请求数
int queuedAsyncCount = dispatcher.queuedCallsCount();
// 获取正在运行的同步请求数
int runningSyncCount = dispatcher.runningCallsCount();
2.7.2 事件监听器监控
OkHttpClient client = new OkHttpClient.Builder()
.eventListener(new EventListener() {
@Override
public void callStart(Call call) {
// 请求开始
}
@Override
public void callEnd(Call call) {
// 请求结束
}
@Override
public void callFailed(Call call, IOException ioe) {
// 请求失败
}
})
.build();
本章小结
-
同步请求流程:
- 调用
execute()方法 - 加入同步运行队列
- 通过拦截器链执行请求
- 完成后移出队列
- 调用
-
异步请求流程:
- 调用
enqueue()方法 - 根据调度策略进入就绪队列或直接执行
- 线程池执行实际请求
- 完成后回调结果
- 调用
-
Dispatcher核心功能:
- 管理三个队列(准备异步、运行异步、运行同步)
- 控制并发请求数量
- 提供请求取消机制
-
线程池特点:
- 无核心线程,最大线程数无限
- 60秒空闲回收
- 使用SynchronousQueue保证任务即时执行
-
性能调优:
- 调整最大并发数和主机并发数
- 自定义线程池参数
- 监控请求队列状态
在下一章中,我们将深入分析OkHttp的核心——拦截器链,揭示请求如何通过责任链模式被处理,以及每个关键拦截器的实现细节。