TaskRunner为OkHttp中的网络通信创建线程,它使用一个线程池,创建线程用以处理OkHttp交付的网络通信任务。
一、TaskRunner概览
BackEnd:网络任务的处理器,用于处理网络任务。它包含了一个线程池,此线程池的核心线程数量为0,最大线程数量为Integer.MAX_VALUE,任务队列为一个容量为0的阻塞队列。
Task:网络任务
TaskQueue:是一个任务队列,包含了多个网络任务,对网络任务进行管理
readyQueues:就绪任务队列所在的队列,包含了多个已就绪的任务队列
busyQueues:正在执行的任务队列所在的队列
TaskRunner的执行流程
1、初始化线程池。此线程池的核心线程数量为0,最大线程数量为Integer.MAX_VALUE,任务队列为一个容量为0的阻塞队列。
2、寻找可执行的任务,并执行。在readyQueues中寻找可以执行的任务,将任务所在的队列转移到busyQueues中,并执行任务。若找到多个可执行的任务,则会利用线程池新建一个线程,加快任务的处理。
3、处理已执行完成的任务。根据任务的返回值,判断任务是否需要再次处理(返回值为-1,则不需要)。将结束任务所在的队列转移到readyQueues中。
4、循环执行2、3。
二、TaskRunner代码分析
1、初始化线程池
companion object {
@JvmField
val INSTANCE = TaskRunner(RealBackend(threadFactory("$okHttpName TaskRunner", daemon = true)))
val logger: Logger = Logger.getLogger(TaskRunner::class.java.name)
}
......
class RealBackend(threadFactory: ThreadFactory) : Backend {
private val executor = ThreadPoolExecutor(
0, // corePoolSize.
Int.MAX_VALUE, // maximumPoolSize.
60L, TimeUnit.SECONDS, // keepAliveTime.
SynchronousQueue(),
threadFactory
)
可以看出实例化TaskRunner时会传入一个RealBackEnd对象,此对象包含一个线程池
2、提交网络任务
fun start(sendConnectionPreface: Boolean = true, taskRunner: TaskRunner = TaskRunner.INSTANCE) {
if (sendConnectionPreface) {
writer.connectionPreface()
writer.settings(okHttpSettings)
val windowSize = okHttpSettings.initialWindowSize
if (windowSize != DEFAULT_INITIAL_WINDOW_SIZE) {
writer.windowUpdate(0, (windowSize - DEFAULT_INITIAL_WINDOW_SIZE).toLong())
}
}
// Thread doesn't use client Dispatcher, since it is scoped potentially across clients via
// 提交网络任务
taskRunner.newQueue().execute(name = connectionName, block = readerRunnable)
}
在Okhttp中,Http2Connection的start方法会提交一个网络任务readerRunnable。用来读取服务端返回的数据帧,大体看下readerRunnable的实现。
inner class ReaderRunnable internal constructor(
internal val reader: Http2Reader
) : Http2Reader.Handler, () -> Unit {
override fun invoke() {
var connectionErrorCode = ErrorCode.INTERNAL_ERROR
var streamErrorCode = ErrorCode.INTERNAL_ERROR
var errorException: IOException? = null
try {
reader.readConnectionPreface(this)
//循环读取服务端的数据帧
while (reader.nextFrame(false, this)) {
}
connectionErrorCode = ErrorCode.NO_ERROR
streamErrorCode = ErrorCode.CANCEL
} catch (e: IOException) {
errorException = e
connectionErrorCode = ErrorCode.PROTOCOL_ERROR
streamErrorCode = ErrorCode.PROTOCOL_ERROR
}
2.1 新建网络任务队列
在提交网络任务时,会调用newQueue方法新建一个网络任务队列,一般来说,在OkHttp中一个网络任务队列只包含一个网络任务。newQueue方法如下:
fun newQueue(): TaskQueue {
val name = synchronized(this) { nextQueueName++ }
return TaskQueue(this, "Q$name")
}
2.2 提交网络任务到线程池
在新建网络任务队列,调用其的execute方法后,会将任务插入到任务队列中,并将任务队列添加到readyQueue。execute方法代码如下:
inline fun execute(
name: String,
delayNanos: Long = 0L,
cancelable: Boolean = true,
crossinline block: () -> Unit
) {
schedule(object : Task(name, cancelable) {
override fun runOnce(): Long {
block() //循环读取服务端的数据帧
return -1L //表示任务执行完成后,不需要再执行
}
}, delayNanos)
}
接下来会调用schedule方法,将任务添加到任务队列,并发出通知,告知TaskRunner去执行网络任务。schedule方法代码如下:
fun schedule(task: Task, delayNanos: Long = 0L) {
synchronized(taskRunner) {
if (shutdown) {
if (task.cancelable) {
taskLog(task, this) { "schedule canceled (queue is shutdown)" }
return
}
taskLog(task, this) { "schedule failed (queue is shutdown)" }
throw RejectedExecutionException()
}
//添加网络任务
if (scheduleAndDecide(task, delayNanos, recurrence = false)) {
taskRunner.kickCoordinator(this) //通知taskRunner去处理网络任务
}
}
}
scheduleAndDecide方法会添加一个网络任务,具体代码如下:
internal fun scheduleAndDecide(task: Task, delayNanos: Long, recurrence: Boolean): Boolean {
//将task与任务队列关联
task.initQueue(this)
// 计算task的执行时刻
val now = taskRunner.backend.nanoTime()
val executeNanoTime = now + delayNanos
// task已经加入任务队列,且执行时刻早于当前的执行时刻,则直接返回
val existingIndex = futureTasks.indexOf(task)
if (existingIndex != -1) {
if (task.nextExecuteNanoTime <= executeNanoTime) {
taskLog(task, this) { "already scheduled" }
return false
}
//之前添加的task执行时刻较晚,则删除之前的任务
futureTasks.removeAt(existingIndex) // Already scheduled later: reschedule below!
}
......
// 按照执行时刻(从早到晚排序),将任务添加到任务队列中
var insertAt = futureTasks.indexOfFirst { it.nextExecuteNanoTime - now > delayNanos }
if (insertAt == -1) insertAt = futureTasks.size
futureTasks.add(insertAt, task)
//若插入到队列头,表示有新的任务了,提醒taskRunner去执行
return insertAt == 0
}
一般情况下,添加完一个新的task之后,scheduleAndDecide方法会返回true,则接下来执行kickCoordinator方法
internal fun kickCoordinator(taskQueue: TaskQueue) {
this.assertThreadHoldsLock()
if (taskQueue.activeTask == null) {
if (taskQueue.futureTasks.isNotEmpty()) {
//将之前新建的任务队列放到readyQueues中
readyQueues.addIfAbsent(taskQueue)
} else {
readyQueues.remove(taskQueue)
}
}
if (coordinatorWaiting) {
//coordinatorWaiting初始化为false,此步为唤醒无任务可以处理的等待线程
backend.coordinatorNotify(this@TaskRunner)
} else {
//启动新的线程,执行runnable中的代码,以处理网络任务
backend.execute(runnable)
}
}
2.3 启动线程处理任务
在上一步,最后会调用backend的execute方法启动一个线程去处理网络任务,代码如下:
private val runnable: Runnable = object : Runnable {
override fun run() {
while (true) {
//获取就绪的任务
val task = synchronized(this@TaskRunner) {
awaitTaskToRun()
} ?: return
logElapsed(task, task.queue!!) {
var completedNormally = false
try {
//执行网络任务
runTask(task)
completedNormally = true
} finally {
// If the task is crashing start another thread to service the queues.
if (!completedNormally) {
backend.execute(this)
}
}
}
}
}
}
override fun execute(runnable: Runnable) {
//将runnable添加到线程池
executor.execute(runnable)
}
RealBackEnd的execute方法会将runnable添加到线程池中去执行,在执行时,会先调用awaitTaskToRun去获取一个可执行的任务,awaitTaskToRun方法的代码如下:
fun awaitTaskToRun(): Task? {
this.assertThreadHoldsLock()
while (true) {
if (readyQueues.isEmpty()) {
return null // Nothing to do.
}
val now = backend.nanoTime()
var minDelayNanos = Long.MAX_VALUE
var readyTask: Task? = null
var multipleReadyTasks = false
// 决定执行哪个任务. 此循环的目标如下:
// * 若有任务,当前线程执行任务;若无任务,当前线程睡眠
// * 若有2个以上的可执行任务,启动另一个线程,加快任务的处理
eachQueue@ for (queue in readyQueues) {
val candidate = queue.futureTasks[0]
val candidateDelay = maxOf(0L, candidate.nextExecuteNanoTime - now)
when {
// 根据执行时刻,判断任务是否可执行
candidateDelay > 0L -> {
minDelayNanos = minOf(candidateDelay, minDelayNanos)
continue@eachQueue
}
// 已找到2个任务了,停止寻找可执行任务,设置标志以启动另一个线程
readyTask != null -> {
multipleReadyTasks = true
break@eachQueue
}
// 记录可执行任务
else -> {
readyTask = candidate
}
}
}
// Implement the decision.
when {
// We have a task ready to go. Get ready.
readyTask != null -> {
//将任务队列转移到busyQueues
beforeRun(readyTask)
// 启动另一个线程,加快任务的处理
if (multipleReadyTasks || !coordinatorWaiting && readyQueues.isNotEmpty()) {
backend.execute(runnable)
}
//返回一个可以执行的任务
return readyTask
}
// Notify the coordinator of a task that's coming up soon.
coordinatorWaiting -> {
if (minDelayNanos < coordinatorWakeUpAt - now) {
backend.coordinatorNotify(this@TaskRunner)
}
return null
}
// 无可执行任务,进行等待,并设置等待时间
else -> {
coordinatorWaiting = true
coordinatorWakeUpAt = now + minDelayNanos
try {
backend.coordinatorWait(this@TaskRunner, minDelayNanos)
} catch (_: InterruptedException) {
// Will cause all tasks to exit unless more are scheduled!
cancelAll()
} finally {
coordinatorWaiting = false
}
}
}
}
}
接下来,获取到任务后,就可以调用runTask方法进行执行
private fun runTask(task: Task) {
this.assertThreadDoesntHoldLock()
val currentThread = Thread.currentThread()
val oldName = currentThread.name
currentThread.name = task.name
var delayNanos = -1L
try {
delayNanos = task.runOnce()
} finally {
synchronized(this) {
//任务执行完成后,将任务队列转移到readyQueues
afterRun(task, delayNanos)
}
currentThread.name = oldName
}
}
至此,TaskRunner任务处理流程结束。