4. 协程超时

任务说明

本案例实现一个网络请求模拟器,使用withTimeout为耗时操作设置超时上限。当操作执行时间超过设定阈值时,协程会被取消并抛出TimeoutCancellationException,从而避免无限期等待。

核心实现

import kotlinx.coroutines.*
import kotlin.system.measureTimeMillis

fun main() = runBlocking {
    // 模拟耗时操作:延迟2秒后返回结果
    suspend fun fetchUserData(): String {
        delay(2000) // 模拟网络请求耗时
        return "用户数据加载完成"
    }

    println("开始请求用户数据...")

    val elapsed = measureTimeMillis {
        try {
            // 设置1秒超时,而请求需要2秒,必然触发超时
            val result = withTimeout(1000) {
                fetchUserData()
            }
            println("请求成功: $result")
        } catch (e: TimeoutCancellationException) {
            println("请求超时: ${e.message}")
            println("异常类型: ${e::class.simpleName}")
        }
    }

    println("总耗时: ${elapsed}ms")

    // 演示超时后协程已被取消
    println("协程是否活跃: ${coroutineContext.isActive}")
}

代码说明

withTimeout接收一个毫秒级超时参数和一个挂起函数块。当块内代码执行时间超过设定值时,协程会被自动取消,并抛出TimeoutCancellationException。该异常是CancellationException的子类,因此必须使用try-catch捕获,否则会导致协程静默取消。

运行方式

# 在项目build.gradle.kts中添加依赖
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")

# 直接运行main函数
kotlin TimeoutExample.kt

验证方法

运行程序后,观察控制台输出。预期输出顺序为:

开始请求用户数据...
请求超时: Timed out waiting for 1000 ms
异常类型: TimeoutCancellationException
总耗时: 约1000ms
协程是否活跃: true

判定标准:程序在约1秒后终止,捕获到TimeoutCancellationException,且总耗时接近超时设定值而非请求的2秒,说明超时机制生效。

withTimeout 超时执行时序 调用方 withTimeout fetchUserData withTimeout(1000) delay(2000) 1000ms 超时触发 取消协程 抛出 TimeoutCancellationException 正常调用 超时取消

关键要点

  • withTimeout超时后会取消协程,但runBlocking外层协程不受影响,程序可继续执行后续代码
  • 必须显式捕获TimeoutCancellationException,否则协程会静默取消且无法感知超时事件
  • 超时时间从withTimeout调用时刻开始计算,而非协程启动时刻