基础使用
我们若要使用到 Kotlin 协程,首先需要添加依赖:
dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
}
然后通过以下代码就可以启动协程:
CoroutineScope(Dispatchers.Main).launch {
}
这样,就能够在主线程中执行代码了。
调度器
而这个调度器不仅只有 Dispatchers.Main
这种,还有:
- Dispatchers.Main
- Dispatchers.Unconfined
- Dispatchers.Default
- Dispatchers.IO
温馨提示:每个调度器里面所写的结论只针对于当前的调度器,并不是针对协程整体来讲
Dispatchers.Main
测试代码:
val startTime = System.currentTimeMillis()
println("--1--${Thread.currentThread().name}--time:${System.currentTimeMillis() - startTime}")
CoroutineScope(Dispatchers.Main).launch {
println("--2--${Thread.currentThread().name}--time:${System.currentTimeMillis() - startTime}")
Thread.sleep(3000)
println("--3--${Thread.currentThread().name}--time:${System.currentTimeMillis() - startTime}")
}
println("--4--${Thread.currentThread().name}--time:${System.currentTimeMillis() - startTime}")
Thread.sleep(3000)
println("--5--${Thread.currentThread().name}--time:${System.currentTimeMillis() - startTime}")
输出结果:
I/System.out: --1--main--time:0
I/System.out: --4--main--time:62
I/System.out: --5--main--time:3064
I/System.out: --2--main--time:3095
I/System.out: --3--main--time:6098
阶段性结论:
- 协程里面的代码在主线程执行。
- 协程外的代码和协程内的代码即使都是在主线程中执行,但是,并不会直接顺序执行,而且继续执行下,等某个时刻再执行协程里面的代码。
- 若协程外的主线程阻塞了,会等主线程阻塞完才会执行协程里面的代码。
不过,在这里有个疑问,就是第二点中的某个时刻该怎么理解?
- 它是一定等协程外的代码执行完才会执行协程里面的代码吗?
- 还是协程外的代码还没完,就会切到协程里面进行执行?
在这里,我模拟下在协程外执行一些耗时的操作:
测试代码:
val startTime = System.currentTimeMillis()
println("--1--${Thread.currentThread().name}--time:${System.currentTimeMillis() - startTime}")
CoroutineScope(Dispatchers.Main).launch {
println("--2--${Thread.currentThread().name}--time:${System.currentTimeMillis() - startTime}")
Thread.sleep(3000)
println("--3--${Thread.currentThread().name}--time:${System.currentTimeMillis() - startTime}")
}
println("--4--${Thread.currentThread().name}--time:${System.currentTimeMillis() - startTime}")
// Thread.sleep(3000)
for(index in 0..10000000000){}
println("--5--${Thread.currentThread().name}--time:${System.currentTimeMillis() - startTime}")
输出结果:
I/System.out: --1--main--time:0
I/System.out: --4--main--time:67
I/System.out: --5--main--time:12738
I/System.out: --2--main--time:12765
I/System.out: --3--main--time:15766
可以初步理解为:只有协程外部的代码执行完才会执行协程内部的代码
Dispatchers.Main
总结:
- 协程里面的代码在主线程执行。
- 协程外的代码和协程内的代码即使都是在主线程中执行,但是,并不会直接顺序执行,而且继续执行下去。
- 若协程外的主线程阻塞了,会等主线程阻塞完才会执行协程里面的代码。
- 只有协程外部的代码执行完才会执行协程内部的代码
Dispatchers.Unconfined
测试代码:
val startTime = System.currentTimeMillis()
println("--1--${Thread.currentThread().name}--time:${System.currentTimeMillis() - startTime}")
CoroutineScope(Dispatchers.Unconfined).launch {
println("--2--${Thread.currentThread().name}--time:${System.currentTimeMillis() - startTime}")
Thread.sleep(3000)
println("--3--${Thread.currentThread().name}--time:${System.currentTimeMillis() - startTime}")
}
println("--4--${Thread.currentThread().name}--time:${System.currentTimeMillis() - startTime}")
for(index in 0..10000000000){}
println("--5--${Thread.currentThread().name}--time:${System.currentTimeMillis() - startTime}")
输出结果:
I/System.out: --1--main--time:0
I/System.out: --2--main--time:52
I/System.out: --3--main--time:3053
I/System.out: --4--main--time:3054
I/System.out: --5--main--time:15267
阶段性结论:
- 在主线程中执行。
- 能跟协程外部的代码顺序执行下去。
不过这里有一个很明显的问题,既然是顺序执行下去,那么,Dispatchers.Unconfined
还有什么意义?
另外,若外部线程不是主线程,那么,Dispatchers.Unconfined
还会是在主线程执行吗?还会顺序执行吗?
在这里,我尝试在子线程中执行 Dispatchers.Unconfined
,并且在 Dispatchers.Unconfined
中执行挂起操作:
测试代码:
Thread {
val startTime = System.currentTimeMillis()
println("--1--${Thread.currentThread().name}--time:${System.currentTimeMillis() - startTime}")
CoroutineScope(Dispatchers.Unconfined).launch {
println("--2--${Thread.currentThread().name}--time:${System.currentTimeMillis() - startTime}")
// Thread.sleep(3000)
withContext(Dispatchers.IO) {
}
println("--3--${Thread.currentThread().name}--time:${System.currentTimeMillis() - startTime}")
}
println("--4--${Thread.currentThread().name}--time:${System.currentTimeMillis() - startTime}")
for (index in 0..10000000000) {
}
println("--5--${Thread.currentThread().name}--time:${System.currentTimeMillis() - startTime}")
}.start()
输出结果:
I/System.out: --1--Thread-2--time:0
I/System.out: --2--Thread-2--time:155
I/System.out: --4--Thread-2--time:284
I/System.out: --3--DefaultDispatcher-worker-1--time:286
I/System.out: --5--Thread-2--time:18155
阶段性结论:
- Dispatchers.Unconfined 并不是一定会在主线程执行,而是会延续协程外的线程,并通过在遇到挂起操作前顺序执行。
- Dispatchers.Unconfined 的代码并不是一直在同个线程中执行,在遇到挂起操作之后,会开启新的线程去执行代码。
Dispatchers.Unconfined
总结:
- 协程里面的代码在遇到挂起操作之前,会延续协程外的线程进行顺序执行。
- 在遇到挂起操作之后,会开启新的线程去执行代码。
Dispatchers.Default、Dispatchers.IO
测试代码:
Thread {
val startTime = System.currentTimeMillis()
println("--1--${Thread.currentThread().name}--time:${System.currentTimeMillis() - startTime}")
CoroutineScope(Dispatchers.Default).launch {
println("--2--${Thread.currentThread().name}--time:${System.currentTimeMillis() - startTime}")
// Thread.sleep(3000)
withContext(Dispatchers.IO) {
}
println("--3--${Thread.currentThread().name}--time:${System.currentTimeMillis() - startTime}")
}
println("--4--${Thread.currentThread().name}--time:${System.currentTimeMillis() - startTime}")
for (index in 0..10000000000) {
}
println("--5--${Thread.currentThread().name}--time:${System.currentTimeMillis() - startTime}")
}.start()
输出结果:
I/System.out: --1--Thread-2--time:0
I/System.out: --4--Thread-2--time:117
I/System.out: --2--DefaultDispatcher-worker-1--time:120
I/System.out: --3--DefaultDispatcher-worker-1--time:174
I/System.out: --5--Thread-2--time:16104
Dispatchers.Default、Dispatchers.IO
总结:
- 协程里面的代码会重新开启一个线程进行执行,非主线程。