private fun promoteAndExecute(): Boolean {
val executableCalls = mutableListOf()
val isRunning: Boolean
synchronized(this) {
val i = readyAsyncCalls.iterator()
//遍历readyAsyncCalls
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.
//符合条件 从readyAsyncCalls列表中删除
i.remove()
//per host 计数加1
asyncCall.callsPerHost().incrementAndGet()
executableCalls.add(asyncCall)
//移入runningAsyncCalls列表
runningAsyncCalls.add(asyncCall)
}
isRunning = runningCallsCount() > 0
}
for (i in 0 until executableCalls.size) {
val asyncCall = executableCalls[i]
//提交任务到线程池
asyncCall.executeOn(executorService)
}
return isRunning
}
这个方法在enqueue和finish方法中都会调用,即当有新的请求入队和当前请求完成后,需要重新提交一遍任务到线程池。
讲了半天线程池,那OkHttp内部到底用的什么线程池呢?
#Dispatcher
@get:JvmName(“executorService”) val executorService: ExecutorService
get() {
if (executorServiceOrNull == null) {
executorServiceOrNull = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS,
SynchronousQueue(), threadFactory(“OkHttp Dispatcher”, false))
}
return executorServiceOrNull!!
}
这不是一个newCachedThreadPool吗?没错,除了最后一个threadFactory参数之外与newCachedThreadPool一毛一样,只不过是设置了线程名字而已,用于排查问题。
阻塞队列用的SynchronousQueue,它的特点是不存储数据,当添加一个元素时,必须等待一个消费线程取出它,否则一直阻塞,如果当前有空闲线程则直接在这个空闲线程执行,如果没有则新启动一个线程执行任务。通常用于需要快速响应任务的场景,在网络请求要求低延迟的大背景下比较合适,详见旧文 Java线程池工作原理浅析。
继续回到主线,第二步比较复杂我们先跳过,来看第三步。
第三步
调用Dispatcher的finished方法
//异步任务执行结束
internal fun finished(call: AsyncCall) {
call.callsPerHost().decrementAndGet()
finished(runningAsyncCalls, call)
}
//同步任务执行结束
internal fun finished(call: RealCall) {
finished(runningSyncCalls, call)
}
//同步异步任务 统一汇总到这里
private fun finished(calls: Deque, call: T) {
val idleCallback: Runnable?
synchronized(this) {
//将完成的任务从队列中删除
if (!calls.remove(call)) throw AssertionError(“Call wasn’t in-flight!”)
idleCallback = this.idleCallback
}
//这个方法在第一步中已经分析,用于将等待队列中的请求移入异步队列,并交由线程池执行。
val isRunning = promoteAndExecute()
//如果没有请求需要执行,回调闲置callback
if (!isRunning && idleCallback != null) {
idleCallback.run()
}
}
第二步
现在我们回过头来看最复杂的第二步,调用getResponseWithInterceptorChain方法,这也是整个OkHttp实现责任链模式的核心。