suspend fun的使用与注意点
suspend fun,会挂起当前协程,不阻塞线程。
它能挂起当前协程的执行流程,但不会阻塞协程所在的线程,这也是协程相比线程更轻量、更高效的核心原因之一。
挂起vs阻塞
阻塞(Block):线程停在原地等待任务完成(比如网络请求、文件读写),这段时间线程什么都做不了,CPU 资源被浪费。
挂起(Suspend):协程暂时 “暂停” 执行,但线程会被释放去执行其他协程;等挂起函数的任务完成(比如网络请求返回),协程会被恢复,线程再回来继续执行这个协程剩下的逻辑。
// Kotlin DSL 示例(build.gradle.kts) dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3") // 安卓项目需加这个 }
import kotlinx.coroutines.* import kotlin.system.measureTimeMillis // 定义挂起函数:模拟耗时操作(比如网络请求、数据库查询) suspend fun doLongTask(taskName: String, delayTime: Long): String { // delay 是 Kotlin 内置的挂起函数,只会挂起协程,不阻塞线程 delay(delayTime) return "任务 $taskName 完成" } fun main() = runBlocking { // 启动主协程(仅用于示例,实际开发中避免在主线程用 runBlocking) val threadName = Thread.currentThread().name println("主线程名称:$threadName") // 输出:main val time = measureTimeMillis { // 同时启动两个协程,执行挂起函数 val job1 = launch { println("协程1运行在线程:${Thread.currentThread().name}") // 输出:main val result1 = doLongTask("A", 1000) println(result1) } val job2 = launch { println("协程2运行在线程:${Thread.currentThread().name}") // 输出:main val result2 = doLongTask("B", 1000) println(result2) } job1.join() job2.join() } println("总耗时:$time ms") // 输出约 1000ms,说明两个任务并发执行,线程未阻塞 }
代码解释:
1、delay(delayTime):Kotlin 协程内置的挂起函数,模拟耗时操作;它和 Thread.sleep() 的区别是:delay 只挂起协程,线程继续工作;Thread.sleep() 会阻塞线程,线程啥也干不了。
2、示例中两个协程都运行在 main 线程,但总耗时只有约 1000ms,证明线程没有被阻塞,而是在协程挂起期间去执行另一个协程的逻辑了。
suspend fun核心注意点:
1、挂起函数不能直接在普通函数中调用:必须在协程(如 launch、async、runBlocking)或其他挂起函数中调用,否则编译器会报错。
2、挂起函数的 “挂起” 是协程层面的:线程本身不会被挂起,协程调度器会把空闲的线程分配给其他协程使用,这是协程高效的关键。
3、如果挂起函数中调用了阻塞式 API(如 Thread.sleep、Java 的同步 IO):即使是挂起函数,也会阻塞线程!此时需要用 withContext(Dispatchers.IO) 等方式将阻塞操作切换到后台线程,避免影响主线程。
总结:
1、suspend fun 定义挂起函数,其核心作用是挂起协程执行,但不阻塞线程,线程可复用执行其他协程。
2、挂起函数只能在协程或其他挂起函数中调用,内置的 delay() 是典型的非阻塞挂起函数。
3、若挂起函数中包含阻塞式操作,需通过 withContext 切换调度器,避免线程阻塞。

浙公网安备 33010602011771号