OkHttp源码学习之TaskRunner

174 阅读3分钟

1. TaskRunner 的核心作用

TaskRunner 的主要功能是:

  1. 管理异步任务

    • OkHttp 内部的许多操作是异步的,例如定时任务、HTTP/2 的流处理、连接池的清理等。
    • TaskRunner 提供了统一的任务管理机制。
  2. 优化线程资源

    • 避免为每个任务创建新线程,提升资源利用率。
    • 使用线程池来复用线程,减少开销。
  3. 任务调度

    • 提供延时任务和周期性任务的调度能力。
  4. 可靠性和稳定性

    • 通过单一的调度器统一管理任务,降低多线程竞态条件的风险。

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 秒
}