kotlin协程的作用
kotlin协程是用来简化异步程序设计的。
通常我们编写异步程序,面临两个问题。
一是异步程序结果的获取阻塞主流程。
二是异步程序结果的获取脱离主流程。
异步程序结果的获取阻塞主流程
fun useFuture() {
val executor = Executors.newCachedThreadPool()
val future = executor.submit<String> {
Thread.sleep(1000)
"result"
}
val result = future.get()//主流程阻塞在这里了
println(result)
}
异步程序结果的获取脱离主流程
fun useCompletableFuture() {
val completableFuture = CompletableFuture.supplyAsync {
Thread.sleep(1000)
"1"
}.thenAccept {//通过回调获取异步程序的结果,脱离了主调用流程
println(it)
}
println("2")
completableFuture.join()//避免程序提前结束
}
kotlin对异步程序结果的获取
我们这里获取异步程序的结果,没有使用回调,而是在异步代码的下方(在主流程中),所以没有脱离主调用流程。 而且defer.await是非阻塞式挂起,并没有阻塞。
GlobalScope.launch {
val defer = async(Dispatchers.IO) {
println("1")
Thread.sleep(1000)
println("2")
"3"
}
println(defer.await())
}
阻塞式地等待结果和使用挂起非阻塞式等待结果的区别
如果我们简单地来看,不管是阻塞式地还是非阻塞的,程序都停在等待结果的地方,好像没有什么区别
fun useFuture() {
val executor = Executors.newCachedThreadPool()
val future = executor.submit<String> {
Thread.sleep(1000)
"result"
}
val result = future.get()//主流程阻塞在这里了,等待
println(result)
}
GlobalScope.launch {
val defer = async(Dispatchers.IO) {
println("1")
Thread.sleep(1000)
println("2")
"3"
}
println(defer.await())//等待结果
}
但是我们看看下面的例子
阻塞式
val newSingleThreadContext = newSingleThreadContext("single thread")
GlobalScope.launch(newSingleThreadContext) {
"1".log()
Thread.sleep(5000)
"2".log()
}
GlobalScope.launch(newSingleThreadContext) {
"3".log()
}
useful info single thread @coroutine#1 256826006 1 //这里执行后停留5秒
useful info single thread @coroutine#1 256826006 2
useful info single thread @coroutine#2 256826006 3
非阻塞式
val newSingleThreadContext = newSingleThreadContext("single thread")
GlobalScope.launch(newSingleThreadContext) {
"1".log()
delay(5000)
"2".log()
}
GlobalScope.launch(newSingleThreadContext) {
"3".log()
}
useful info single thread @coroutine#1 793035649 1
useful info single thread @coroutine#2 793035649 3 //这里执行后停留5秒
useful info single thread @coroutine#1 793035649 2
如果线程被阻塞了,那么线程就不能干任何事情了
但是如果使用非阻塞式地挂起,那么协程被挂起过后,线程还可以去执行另一个协程