1. TaskRunner 的核心作用
TaskRunner 的主要功能是:
-
管理异步任务:
- OkHttp 内部的许多操作是异步的,例如定时任务、HTTP/2 的流处理、连接池的清理等。
TaskRunner提供了统一的任务管理机制。
-
优化线程资源:
- 避免为每个任务创建新线程,提升资源利用率。
- 使用线程池来复用线程,减少开销。
-
任务调度:
- 提供延时任务和周期性任务的调度能力。
-
可靠性和稳定性:
- 通过单一的调度器统一管理任务,降低多线程竞态条件的风险。
2. TaskRunner 的核心类与架构
TaskRunner:负责任务的全局管理,是调度的核心。TaskQueue:每个任务队列绑定到一个TaskRunner,用于存放具体的任务。Task:具体的任务逻辑,由TaskRunner调度执行。
核心架构图:
TaskRunner
├── TaskQueue1 ─── Task1, Task2, ...
├── TaskQueue2 ─── Task3, Task4, ...
└── TaskQueueN ─── TaskN, TaskN+1, ...
3. TaskRunner 的实现
1. 创建 TaskRunner
TaskRunner 是通过单例模式初始化的,通常不需要手动创建。
val taskRunner = TaskRunner.INSTANCE
2. 任务队列 TaskQueue
每个 TaskQueue 用于管理一组相关的任务,比如一个 HTTP/2 连接可能有自己的任务队列。
val queue = taskRunner.newQueue()
3. 添加任务 Task
任务是通过 Task 类定义的,并由 TaskQueue 提交给 TaskRunner。
val task = object : Task("Example Task") {
override fun runOnce(): Long {
println("Task is running")
return -1 // 返回下次执行时间(毫秒),-1 表示任务结束
}
}
queue.schedule(task, 1000L) // 延迟 1 秒后执行任务
4. TaskRunner 的关键特性
1. 任务优先级
- 任务被分配到不同的队列中,各队列之间是独立的。
TaskRunner按顺序调度每个队列的任务,确保队列内部的任务按添加顺序执行。
2. 支持延迟与周期性任务
-
延迟任务:
queue.schedule(task, delayMillis = 1000L) -
周期性任务: 在
runOnce()中返回下次执行的延迟时间(毫秒)。
3. 全局资源复用
TaskRunner使用单一线程池管理任务,避免过多线程的创建,提升系统效率。
5. TaskRunner 在 OkHttp 中的应用场景
1. 连接池管理
- 定期清理空闲连接。
- 确保连接池资源高效利用。
2. HTTP/2 流管理
- 处理 HTTP/2 流的异步任务,如心跳检测、流关闭等。
3. DNS 预解析
- 异步解析域名,提升请求速度。
4. 定时任务
- 比如超时检测、连接超时等。
6. TaskRunner 的常见问题与注意事项
问题 1:如何保证任务按顺序执行?
- 每个
TaskQueue内部的任务按提交顺序执行。 - 不同队列的任务可能并发执行。
问题 2:如何停止任务?
-
如果任务是周期性的,在
runOnce()返回-1表示任务结束。 -
也可以通过清空队列的方式停止所有任务:
queue.cancelAll()
问题 3:性能问题
- 如果大量任务堆积,可能会导致任务延迟或线程池饱和。需要合理设置任务队列的使用方式。
7. 示例代码
import okhttp3.internal.concurrent.Task
import okhttp3.internal.concurrent.TaskRunner
fun main() {
val taskRunner = TaskRunner.INSTANCE
val queue = taskRunner.newQueue()
val task = object : Task("Example Task") {
override fun runOnce(): Long {
println("Task is running at ${System.currentTimeMillis()}")
return -1 // 返回 -1 结束任务
}
}
// 延迟 2 秒后执行任务
queue.schedule(task, 2000L)
// 添加一个周期性任务,每 3 秒执行一次
val repeatingTask = object : Task("Repeating Task") {
override fun runOnce(): Long {
println("Repeating task at ${System.currentTimeMillis()}")
return 3000L // 下次延迟 3 秒
}
}
queue.schedule(repeatingTask, 1000L) // 初始延迟 1 秒
}