不阻塞线程

阻塞线程 = 线程被"钉死"在原地,干瞪眼等着,别的啥也干不了

不阻塞线程 = 线程标记一下"这事我记着,先去干别的",等条件满足了再回来继续


用餐厅服务员类比

假设一个服务员(线程)要服务两桌客人:

阻塞(Blocking)

服务员给A桌下单后,站在收银台前一动不动,盯着出餐口等菜做好。B桌客人喊破喉咙他也听不见,因为他人被"卡"在这了。

kotlin

复制代码
// 阻塞线程:线程干等着,啥也不干
fun fetchData(): String {
    val response = httpClient.execute(request)  // 线程卡在这里等网络响应
    // 网络没回来之前,这行代码下面的都执行不了
    return response.body
}

不阻塞 / 挂起(Non-blocking / Suspend)

服务员给A桌下单后,记在小本上,转身去给B桌点菜、给C桌加水。后厨喊"A桌好了",他再回来端菜。

kotlin

复制代码
// 挂起协程:线程被释放,可以去执行其他协程
suspend fun fetchData(): String {
    val response = httpClient.executeAsync(request).await()  // 协程挂起
    // 等待期间,线程去执行别的协程任务了
    return response.body
}

代码层面的区别

表格

阻塞线程 不阻塞线程(挂起)
线程状态 RUNNABLE 但卡在等待,CPU 空转或内核挂起 协程挂起,线程被释放去执行别的任务
资源占用 占着线程不干活 线程可以服务其他协程
代码写法 直接调用函数 需要 suspend + await
并发能力 1个线程只能做1件事 1个线程可以同时"跟进"上百个协程

一个更直观的对比

kotlin

复制代码
// ========== 阻塞线程 ==========
fun blockingWay() {
    val result1 = fetchFromNetwork()  // 耗时2秒,线程卡死2秒
    val result2 = fetchFromNetwork()  // 再卡2秒
    // 总共4秒,线程全程被占着
}

// ========== 不阻塞线程 ==========
suspend fun nonBlockingWay() = coroutineScope {
    val deferred1 = async { fetchFromNetworkAsync() }  // 启动,不等待
    val deferred2 = async { fetchFromNetworkAsync() }  // 立刻启动第二个
    
    val result1 = deferred1.await()  // 如果需要,这里挂起协程(不是线程)
    val result2 = deferred2.await()
    // 两个请求同时发,大约2秒完成,等待期间线程去干别的了
}

一句话总结

阻塞线程 是"人(线程)被活拴在一件事上,别的干不了";

不阻塞线程是"事(协程)被挂起来记着,人(线程)先去忙别的,回头再来"。

协程的 await 挂起的是协程 ,释放的是线程。这是它能用少量线程处理大量并发请求的根本原因。

相关推荐
_阿南_3 小时前
flutter 展示的字体突然奔放了
android·flutter·ios
唐青枫4 小时前
Kotlin interface 详解:别再把接口写成空壳和万能开关
kotlin
文人sec6 小时前
MySQL事务与索引做了什么?
android·笔记·mysql
刘洋浪子6 小时前
AndroidStudio保存日志菜单
android
朱涛的自习室6 小时前
从 Prompt 到 Graph:AI 工程的进化史
android·前端·人工智能
2501_932750267 小时前
Android 中 Serializable 与 Parcelable 的对比与选择
android
dalong109 小时前
Savitzky-Golay 的C# 实现
开发语言·kotlin·c#
157092511349 小时前
ViewBinding与DataBinding区别与选型
android
小乖写代码10 小时前
49款开源Android小游戏
android·游戏