创建协程的三种方式
- runBlocking
运行一个协程并且会阻塞当前线程,直到它完成。- launch
启动一个新的协程,不会阻塞当前线程,并且返回一个Job,可以取消。- async
async和await是两个函数,这两个函数在我们使用过程中一般都是成对出现的。
async用于启动一个异步的协程任务,await用于去得到协程任务结束时返回的结果,结果是通过一个Deferred对象返回的。
在概念上,async 就类似于 launch。它启动了一个单独的协程,这是一个轻量级的线程并与其它所有的协程一起并发的工作。不同之处在于 launch 返回一个 Job 并且不附带任何结果值,而 async 返回一个 Deferred —— 一个轻量级的非阻塞 future, 这代表了一个将会在稍后提供结果的 promise。可以使用 .await() 在一个延期的值上得到它的最终结果, 但是 Deferred 也是一个 Job,所以如果需要的话,你可以取消它。
CoroutineStart源码
协程的四种启动模式一:DEFAULT
Default——根据上下文立即调度协程执行。
如果协程上下文的[CoroutineDispatcher]从[CoroutineDispatcher. isdispatchneeded]返回’ true ’
函数,然后协程代码被调度以供稍后执行,而代码被调度
被调用的协程构建器继续执行。
注意[Dispatchers。unconstrained总是从它的[CoroutineDispatcher.isDispatchNeeded]返回false
函数,所以用[Dispatchers. *]启动协程。unconstrained [DEFAULT]与使用[un分派]相同。
如果协程[Job]在它有机会开始执行之前被取消,那么它将不会启动它的执行,但将以异常完成。
在挂起点的协同程序的可取消性取决于的具体实现细节暂停功能。使用[suspenpendcancellablecoroutine]实现可取消的挂起函数。
示例
fun main() = runBlocking {
val job = launch (start = CoroutineStart.DEFAULT){
println("开始执行耗时操作...")
delay(2000L)
println("耗时操作结束")
}
delay(1000L)
job.cancel()
println("任务取消了")
}
运行结果
协程的四种启动模式二:LAZY
仅在需要时才惰性地启动协程。
详细信息请参见相应协程构建器的文档
(如[launch][CoroutineScope])。launch]和[async][coroutincope .async])。
如果协程[Job]在它有机会开始执行之前被取消,那么它将不会启动它的执行,但将以异常完成。
fun main() = runBlocking {
val job = async (start = CoroutineStart.LAZY){
println("开始执行耗时操作...")
delay(2000L)
println("耗时操作结束")
}
delay(1000L)
job.cancel()
println("任务取消了")
job.await()
}
运行结果
协程的四种启动模式三:ATOMIC
自动地(即,以一种不可取消的方式)根据上下文调度协程的执行。
这类似于[DEFAULT],但是协程在开始执行之前不能被取消。
在挂起点的协程是否可取消,取决于挂起函数如[DEFAULT]。
@ExperimentalCoroutinesApi //从1.0.0开始,没有稳定性的ETA
fun main() = runBlocking {
val job = async(start = CoroutineStart.ATOMIC) {
println("开始执行耗时操作...")
//在挂起点之前不会被取消
delay(2000L)//这里就是一个挂起点, delay是挂起函数
println("耗时操作结束")
}
delay(1000L)
job.cancel()
println("任务取消了")
}
运行结果
协程的四种启动模式四:UNDISPATCHED
立即执行协程,直到它在当前线程中的第一个挂起点
协程是使用[dispatchers . unconstrained]启动的。但是,当协程从暂停状态恢复时
根据上下文中的[CoroutineDispatcher]进行分派。
这类似于[ATOMIC],因为协程即使已经被取消也会开始执行。
但不同之处在于它在同一个线程中开始执行。
在挂起点的协程是否可取消,取决于挂起函数如[DEFAULT]。
注:这是一个实验性api。当使用此模式时,协程的执行语义可能会在将来发生变化。
@ExperimentalCoroutinesApi //从1.0.0开始,没有稳定性的ETA
fun main() = runBlocking {
val job = async(context = Dispatchers.IO, start = CoroutineStart.UNDISPATCHED) {
println("开始执行耗时操作... ${Thread.currentThread().name}")
//在挂起点之前不会被取消
delay(2000L)//这里就是一个挂起点, delay是挂起函数
println("耗时操作结束...${Thread.currentThread().name}")
}
delay(1000L)
job.cancel()
println("任务取消了...${Thread.currentThread().name}")
}
运行结果
从上图可以看到, async(context = Dispatchers.IO, start = CoroutineStart.UNDISPATCHED) ,但是还在主线程执行的。