第二章:Okhttp 请求调度与执行

177 阅读4分钟

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 异步请求入队流程

deepseek_mermaid_20250717_0c505b.png

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();

本章小结

  1. 同步请求流程

    • 调用execute()方法
    • 加入同步运行队列
    • 通过拦截器链执行请求
    • 完成后移出队列
  2. 异步请求流程

    • 调用enqueue()方法
    • 根据调度策略进入就绪队列或直接执行
    • 线程池执行实际请求
    • 完成后回调结果
  3. Dispatcher核心功能

    • 管理三个队列(准备异步、运行异步、运行同步)
    • 控制并发请求数量
    • 提供请求取消机制
  4. 线程池特点

    • 无核心线程,最大线程数无限
    • 60秒空闲回收
    • 使用SynchronousQueue保证任务即时执行
  5. 性能调优

    • 调整最大并发数和主机并发数
    • 自定义线程池参数
    • 监控请求队列状态

在下一章中,我们将深入分析OkHttp的核心——拦截器链,揭示请求如何通过责任链模式被处理,以及每个关键拦截器的实现细节。