OkHttp 原理解析 - 线程调度

1
2
3
4
// 基本使用

OkHttpClient.newCall(Request).enqueue(Callback)

线程调度

  1. newCall 返回 RealCall 对象

  2. 调用 RealCall 对象的 enqueue 方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // RealCall.class
    override fun enqueue(responseCallback: Callback) {
    synchronized(this) {
    check(!executed) { "Already Executed" }
    executed = true
    }
    callStart() // 调用前期准备,如添加监听
    3. 使用调度器将 call 加入队列,AsyncCall 是 RealCall 内部类,持有 RealCall 对象
    client.dispatcher.enqueue(AsyncCall(responseCallback))
    }
  3. 使用调度器将 call 加入队列

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // Dispatcher.class
    internal fun enqueue(call: AsyncCall) {
    synchronized(this) {
    readyAsyncCalls.add(call)
    if (!call.call.forWebSocket) {
    val existingCall = findExistingCallWithHost(call.host)
    if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
    }
    }
    promoteAndExecute() // 4. 从 readyAsyncCalls 中拿出 call 并放入 runningAsyncCalls,执行任务
    }
  4. promoteAndExecute()
    每当 maxRequests/maxRequestsPerHost/call 调用 enqueue/call finish,都会执行promoteAndExecute()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    private fun promoteAndExecute(): Boolean {
    this.assertThreadDoesntHoldLock()
    val executableCalls = mutableListOf<AsyncCall>()
    val isRunning: Boolean
    synchronized(this) {
    val i = readyAsyncCalls.iterator()
    while (i.hasNext()) {
    val asyncCall = i.next()
    if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity.
    if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.
    i.remove()
    asyncCall.callsPerHost.incrementAndGet()
    // 将 call 加入可执行列表
    executableCalls.add(asyncCall)
    // 将 call 加入运行中列表
    runningAsyncCalls.add(asyncCall)
    }
    isRunning = runningCallsCount() > 0
    }
    for (i in 0 until executableCalls.size) {
    // 遍历可执行列表中的任务并放入线程池 executorService 中执行
    val asyncCall = executableCalls[i]
    asyncCall.executeOn(executorService)
    }
    return isRunning
    }

实用工具

  • 更新token
1
2
3
4
5
6
7
[OkHttpClient].authenticator(object : Authenticator {
override fun authenticate(route: Route?, response: Response): Request? {
return response.request.newBuilder()
.header("Auth", "[NEW_TOKEN]")
.build()
}
})