1.1)依赖 api 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0-M1'
所谓的协程官方介绍如下:
协程通过将复杂性放入库来简化异步编程。程序的逻辑可以在协程中顺序地表达,而底层库会为我们解决其异步性。该库可以将用户代码的相关部分包装为回调、订阅相关事件、在不同线程(甚至不同机器)上调度执行,而代码则保持如同顺序执行一样简单。
1.2) CoroutineScope,CoroutineContext,CoroutineDispatcher,Continuation 学习协程需要知道这几个类:
CoroutineScope-协程作作用域,包含CoroutineContext,可以理解为协程本身
CoroutineContext-It is an indexed set of Element instances.
CoroutineDispatcher-协程调度器,指定协程运行特定的thread or thread pool
Continuation–这个接口表示的是在一个挂起点之后,执行的代码片段,返回一个vaule
2.3)launch,async,withContext,Job , Deferred 启动一个简单的协程可以用launch{}或者async{}
这两者返回的都是Job,区别在于async返回的是Deferred,可以携带协程执行片段的返回值.
两者挂起时,都不会阻塞所在线程.
先看几个使用例子:
eg1:
fun coroutinesRunner() = runBlocking {
test001()
}
private suspend fun test001() {
coroutineScope {
launch(CoroutineName("1")) {
println("launch 01...")
delay(3000)
println("launch01 delay 3000ms")
}.join()
println("---after job finish system exit---")
}
}
输出:
launch 01...
launch01 delay 3000ms
---after job finish system exit---
eg2:
模拟串行场景
private suspend fun test002() {
coroutineScope {
time {
val registerDef = async {
whichThread("registerDef")
println("开始注册...")
delay(3000)
println("注册成功...")
"openId:837983"
}
val loginDef = async {
println("${registerDef.await()},开始登录...")
delay(1000)
println("登录成功...")
"大明星,猪晓阳"
}
println("---------running----------")
println("当前登录用户:${loginDef.await()}")
println("---------end--------------")
}
}
}
输出:
---------running----------
tag:registerDef,threadName=main @coroutine#2
开始注册...
注册成功...
openId:837983,开始登录...
登录成功...
当前登录用户:大明星,猪晓阳
---------end--------------
耗时:4034
--------------next--------------------
registerDef.await()会使协程挂起,等待结果可用时,恢复协程继续执行剩余片段; 可以看到的是,当协程挂起时,线程没有被阻塞,println("---------running----------")还是直接执行了
eg3:
模拟并行场景
private suspend fun test003() {
coroutineScope {
time {
val reqPic01 = async {
println("获取猪晓阳果照片01...")
delay(1500)
println("获取猪晓阳果照片01成功...")
"https://img01.xxx.jpg"
}
val reqPic02 = async {
println("获取猪晓阳果照片02...")
delay(1000)
println("获取猪晓阳果照片02成功...")
"https://img02.xxx.jpg"
}
println(
"图片准备完成===>" +
"pic01=${reqPic01.await()}," +
"pic02=${reqPic02.await()}"
)
}
}
}
输出:
获取猪晓阳果照片01...
获取猪晓阳果照片02...
获取猪晓阳果照片02成功...
获取猪晓阳果照片01成功...
图片准备完成===>pic01=https://img01.xxx.jpg,pic02=https://img02.xxx.jpg
耗时:1529
--------------next--------------------
eg4:
协程同步
private fun test004() {
val mutex = Mutex()
var counter = 0
repeat(1000) {
GlobalScope.launch {
mutex.withLock {
counter++
println(counter)
}
}
}
}
输出:
1
2
3
4
5
6
7
8
9
10
11
12
....
1000
使用Mutex().withLock{}可以保证协程同步,类似java重入锁