扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
五个结论2022-12-24 有错帮忙留言,一块完善进步
创新互联建站基于成都重庆香港及美国等地区分布式IDC机房数据中心构建的电信大带宽,联通大带宽,移动大带宽,多线BGP大带宽租用,是为众多客户提供专业服务器托管报价,主机托管价格性价比高,为金融证券行业西部信息服务器托管,ai人工智能服务器托管提供bgp线路100M独享,G口带宽及机柜租用的专业成都idc公司。
结论一. 协程是一个线程框架,协程依附于线程或者说在线程中执行
结论二. 一个线程中可以启动多个协程,启动的协程不一定运行在该线程
结论三. 一个线程中可以执行多个协程,同一线程的不同协程按照启动先后顺序执行代码,依附不同线程的协程间执行顺序不固定(并发)
结论四. 线程执行到协程的挂起函数时,会暂停该协程的往下执行,此时线程会去执行该线程中的其他协程代码,这个就是"非阻塞式"的含义
结论五. suspend关键字的含义是告诉线程,我这个函数的协程先暂停执行,我要去其他线程执行函数体代码,你先执行其他协程代码,我稍后回来你再执行我的协程
此时若指定suspend函数中代码将要执行线程仍为原线程,则原线程会"置之不理"函数及函数所在协程,协程会一直被挂起,不会再恢复,
若是主线程的话会引起ANR
验证结论二与结论三
测试代码class TestActivity : Activity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
runBlocking {log("协程A--我是runBlocking启动的协程代码,我运行在主线程")
launch {log("协程B--我是launch启动的协程代码,我运行在主线程") }
launch {log("协程C--我是launch启动的协程代码,我运行在主线程") }
launch(Dispatchers.IO) {log("协程D--我是launch启动的协程代码,我运行在IO线程") }
log("协程A--我是runBlocking启动的协程代码,我也运行在主线程")
}
}
}
执行结果第一次执行结果
ThreadHash[540585569] Thread[main,5,main] 协程A--我是runBlocking启动的协程代码,我运行在主线程
ThreadHash[540585569] Thread[main,5,main] 协程A--我是runBlocking启动的协程代码,我也运行在主线程
ThreadHash[540585569] Thread[main,5,main] 协程B--我是launch启动的协程代码,我运行在主线程
ThreadHash[540585569] Thread[main,5,main] 协程C--我是launch启动的协程代码,我运行在主线程
ThreadHash[1632014539] Thread[DefaultDispatcher-worker-1,5,main] 协程D--我是launch启动的协程代码,我运行在IO线程
第二次执行结果
ThreadHash[540585569] Thread[main,5,main] 协程A--我是runBlocking启动的协程代码,我运行在主线程
ThreadHash[540585569] Thread[main,5,main] 协程A--我是runBlocking启动的协程代码,我也运行在主线程
ThreadHash[1346142757] Thread[DefaultDispatcher-worker-1,5,main] 协程D--我是launch启动的协程代码,我运行在IO线程
ThreadHash[540585569] Thread[main,5,main] 协程B--我是launch启动的协程代码,我运行在主线程
ThreadHash[540585569] Thread[main,5,main] 协程C--我是launch启动的协程代码,我运行在主线程
结果分析主线程中启动了A,B,C,D四个协程,协程D运行在IO线程
主线程中执行A,B,C三个协程时,按照A,B,C的启动顺序执行,协程D则跟其他3个协程并发执行
由此得出结论二与结论三
验证结论四
测试代码class TestActivity : Activity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
runBlocking {log("协程A--我是runBlocking启动的协程代码,我运行在主线程")
launch {log("协程B--主线程,开始计算")
var count = 0
repeat(1000000000) {if (it == 500000000) {log("协程B--主线程,遇到了协程B中挂起函数delay,暂停该协程执行其他协程")
delay(500)
log("协程B--主线程,协程delay结束,该协程继续执行")
}
count++
}
count.also {log("协程B--主线程,结束计算")
}
}
launch {log("协程C--主线程,开始计算")
var count = 0
repeat(1000000000) {if (it == 500000000) {log("协程C--主线程,遇到了协程C中挂起函数delay,暂停该协程执行其他协程")
delay(500)
log("协程C--主线程,协程delay结束,该协程继续执行")
}
count++
}
count.also {log("协程C--主线程,结束计算")
}
}
log("协程A--我是runBlocking启动的协程代码,我也运行在主线程")
}
}
}
执行结果16:47:30.516 System.out: ThreadHash[107566656] Thread[main,5,main] 协程A--我是runBlocking启动的协程代码,我运行在主线程
16:47:30.524 System.out: ThreadHash[107566656] Thread[main,5,main] 协程A--我是runBlocking启动的协程代码,我也运行在主线程
16:47:30.525 System.out: ThreadHash[107566656] Thread[main,5,main] 协程B--主线程,开始计算
16:47:36.949 System.out: ThreadHash[107566656] Thread[main,5,main] 协程B--主线程,遇到了协程B中挂起函数delay,暂停该协程执行其他协程
16:47:36.958 System.out: ThreadHash[107566656] Thread[main,5,main] 协程C--主线程,开始计算
16:47:43.384 System.out: ThreadHash[107566656] Thread[main,5,main] 协程C--主线程,遇到了协程C中挂起函数delay,暂停该协程执行其他协程
16:47:43.385 System.out: ThreadHash[107566656] Thread[main,5,main] 协程B--主线程,协程delay结束,该协程继续执行
16:47:49.807 System.out: ThreadHash[107566656] Thread[main,5,main] 协程B--主线程,结束计算
16:47:49.808 System.out: ThreadHash[107566656] Thread[main,5,main] 协程C--主线程,协程delay结束,该协程继续执行
16:47:56.229 System.out: ThreadHash[107566656] Thread[main,5,main] 协程C--主线程,结束计算
结果分析A,B,C三个协程都是主线程协程,先打印了协程A的日志,然后执行协程B,执行过程中遇到挂起函数,协程B被挂起暂停,
此时线程开始执行协程C中代码,执行过程中再遇挂起函数,此时协程B的delay早已经超时,线程继续执行协程B代码,
协程B执行完后继续执行协程C剩余代码
由此得出结论四
验证结论五
测试代码用例一:
class TestActivity : Activity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
runBlocking {log("协程A--我是runBlocking启动的协程代码,我运行在主线程")
withContext(Dispatchers.IO) {log("我是被挂起函数withContext指定在IO线程进行的任务,挂起暂停协程A开始")
var count = 0
repeat(1000000000) {count++
}
log("我是被挂起函数withContext指定在IO线程进行的任务,挂起暂停协程A结束")
}
launch {log("协程B--我是launch启动的协程代码,我运行在主线程") }
launch {log("协程C--我是launch启动的协程代码,我运行在主线程") }
log("协程A--我是runBlocking启动的协程代码,我也运行在主线程")
}
}
}
用例二:
class TestActivity : Activity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
runBlocking {log("协程A--我是runBlocking启动的协程代码,我运行在主线程")
withContext(Dispatchers.Main) {log("我是被挂起函数withContext指定在Main线程进行的任务,挂起暂停协程A开始")
var count = 0
repeat(1000000000) {count++
}
log("我是被挂起函数withContext指定在Main线程进行的任务,挂起暂停协程A结束")
}
launch {log("协程B--我是launch启动的协程代码,我运行在主线程") }
launch {log("协程C--我是launch启动的协程代码,我运行在主线程") }
log("协程A--我是runBlocking启动的协程代码,我也运行在主线程")
}
}
}
执行结果用例一执行结果
17:07:20.334 System.out: ThreadHash[107566656] Thread[main,5,main] 协程A--我是runBlocking启动的协程代码,我运行在主线程
17:07:20.370 System.out: ThreadHash[144796025] Thread[DefaultDispatcher-worker-1,5,main] 我是被挂起函数withContext指定在IO线程进行的任务,挂起暂停协程A开始
17:07:25.683 System.out: ThreadHash[144796025] Thread[DefaultDispatcher-worker-1,5,main] 我是被挂起函数withContext指定在IO线程进行的任务,挂起暂停协程A结束
17:07:25.687 System.out: ThreadHash[107566656] Thread[main,5,main] 协程A--我是runBlocking启动的协程代码,我也运行在主线程
17:07:25.689 System.out: ThreadHash[107566656] Thread[main,5,main] 协程B--我是launch启动的协程代码,我运行在主线程
17:07:25.690 System.out: ThreadHash[107566656] Thread[main,5,main] 协程C--我是launch启动的协程代码,我运行在主线程
用例二执行结果只有下面一行
17:12:45.177 System.out: ThreadHash[107566656] Thread[main,5,main] 协程A--我是runBlocking启动的协程代码,我运行在主线程
结果分析用例一中用withContext挂起函数,指定'函数中代码将要执行线程IO线程' 协程A正常被挂起,然后恢复执行,然后执行协程B协程C
用例二中用withContext挂起函数,指定'函数中代码将要执行线程仍为原线程(主线程)',主线程对函数及函数所在协程 "置之不理"
,协程会一直被挂起,不会再恢复,代码就卡这里了,多点几下应用就ANR了
由此得出结论五
参考文献kotlin官网翻译 https://www.kotlincn.net/docs/reference/coroutines/basics.html
谷歌官网 https://developer.android.google.cn/kotlin/coroutines/coroutines-best-practices
Kotlin协程在Android中的挂起流程 https://maimai.cn/article/detail?fid=1638818450&efid=Bb3L1WdcCTmFgqVubzu92w
Benny Huo https://www.bennyhuo.com/book/kotlin-coroutines/01-intro.html#%E5%85%B3%E4%BA%8E%E4%BD%9C%E8%80%85
可能是最全的Kotlin协程讲解 https://blog.csdn.net/zou8944/article/details/106447727?share_token=b127e799-a6a7-4e2a-9073-6ce2a286e151
一文快速入门 Kotlin 协程 https://juejin.cn/post/6908271959381901325
KOTLIN中的协程,用起来原来这么简单? https://www.freesion.com/article/2493883525/
Kotlin: Suspend挂起 https://blog.csdn.net/qq_39969226/article/details/101058033
【码上开学】Kotlin 协程的挂起好神奇好难懂?今天我把它的皮给扒了 http://www.javashuo.com/article/p-uopxaafq-dd.html
Kotlin协程深入了解一波 http://192.168.120.239:4999/web/#/6/685
Kotlin-协程(4)-启动&分析执行过程 https://juejin.cn/post/6844903822834270215
Kotlin 协程一 —— 协程 Coroutine SharpCJ's blog https://www.cnblogs.com/joy99/p/15805916.html
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流