如果想要在一个非挂起(suspend)方法中调用协程,则需要使用launch或async方式。
launch和async对比
相同点:
- launch 和 async 构建器都可以用于异步执行任务。
它们都可以在协程上下文中启动一个新的协程,并且该协程的执行是异步的,不会阻塞当前线程。 - launch的join()方法、async的await()方法会阻塞当前协程体, 但不会阻塞当前线程。
- Deferred 继承自 Job 接口,Job有的它都有,增加了一个方法 await ,这个方法接收的是 async 闭包中返回的值
唯一不同点:返回值不同
- launch的Job携带返回值,async的Deferred携带返回值
runBlocking
launch和async不会阻塞当前线程,但runBlocking会阻塞当前线程
首先,我们定义一个挂起函数用于演示
//域名解析是一个耗时操作,故用协程实现
private suspend fun analysisDns() = suspendCancellableCoroutine<String> {
thread {
try {
val ipAddress = InetAddress.getByName("www.baidu.com")
showLog(2, ipAddress.hostAddress)
it.resume(ipAddress.hostAddress)
} catch (e: Exception) {
it.resume("解析失败: $e")
}
}
}
//输出日志,以及当前线程
fun showLog(i: Int, msg: String = "") {
println("$i --- ${
Thread.currentThread().name} $msg")
}
//防止程序过早结束,看不到效果
private fun end() {
print("\n----------------------------- 输入任意键结束 -----------------------------\n\n")
readLine()
}
1、Launch
定义
val testLaunch: () -> Unit = {
showLog(0)
GlobalScope.launch {
showLog(1)
analysisDns()
showLog(3)
}
showLog(4)
}
使用
fun main() {
testLaunch.invoke()
end()
}
日志输出
0 --- main
4 --- main
----------------------------- 输入任意键结束 -----------------------------
1 --- DefaultDispatcher-worker-2
2 --- Thread-2 14.119.104.189
3 --- DefaultDispatcher-worker-2
Process finished with exit code 0
- launch 异步执行,无需返回结果,不会阻塞当前线程
- 0, 4当前线程, 不会被阻塞
- 若不使用end()函数,则只会输出0,4后程序便结束。
2、Launch Join()
定义
val testLaunchJoin: () -> Unit = {
showLog(-1)
GlobalScope.launch {
showLog(0)
val job = GlobalScope.launch {
showLog(1)
analysisDns()
showLog(3)
}
showLog(4)
job.join()
showLog(5)
}
showLog(6)
}
使用
fun main() {
testLaunchJoin.invoke()
end()
}
日志输出
-1 --- main
6 --- main
----------------------------- 输入任意键结束 -----------------------------
0 --- DefaultDispatcher-worker-1
4 --- DefaultDispatcher-worker-1
1 --- DefaultDispatcher-worker-2
2 --- Thread-2 14.119.104.189
3 --- DefaultDispatcher-worker-1
5 --- DefaultDispatcher-worker-1
Process finished with exit code 0
- launch的join()方法,要在协程体内才可调用
- join()会阻塞当前协程体, 不会阻塞当前线程
- -1, 6是当前线程 ,不会被阻塞
- 0, 4, 5是join所在协程, 会被阻塞
3、Async
定义
val testAsync: () -> Unit = {
showLog(0)
GlobalScope.async {
showLog(1)
analysisDns()
showLog(3)
}
showLog(4)
}
使用
fun main() {
testAsync.invoke()
end()
}
日志输出
0 --- main
4 --- main
----------------------------- 输入任意键结束 -----------------------------
1 --- DefaultDispatcher-worker-1
2 --- Thread-2 14.119.104.254
3 --- DefaultDispatcher-worker-1
Process finished with exit code 0
- async 异步执行,lambda最后一行为返回结果,不会阻塞当前线程
- 0, 4当前线程, 不会被阻塞
4、Async Await()
定义
val testAsyncAwait: () -> Unit = {
showLog(-1)
GlobalScope.launch {
showLog(0)
val deferred = GlobalScope.async {
showLog(1)
analysisDns()
showLog(3)
"Deferred返回值"
}
showLog(4)
val res = deferred.await()
showLog(5, res)
}
showLog(6)
}
使用
fun main() {
testAsyncAwait.invoke()
end()
}
日志输出
-1 --- main
6 --- main
----------------------------- 输入任意键结束 -----------------------------
0 --- DefaultDispatcher-worker-2
4 --- DefaultDispatcher-worker-2
1 --- DefaultDispatcher-worker-1
2 --- Thread-2 14.119.104.254
3 --- DefaultDispatcher-worker-2
5 --- DefaultDispatcher-worker-2 Deferred返回值
Process finished with exit code 0
- async的await()方法,要在协程体内才可调用
- await()会阻塞当前协程体, 不会阻塞当前线程
- -1, 6是当前线程 ,不会被阻塞
- 0, 4, 5是join所在协程, 会被阻塞
5、Runblocking
定义
val testRunBlocking: () -> Unit = {
showLog(0)
runBlocking {
showLog(1)
analysisDns()
showLog(3)
}
showLog(4)
}
使用
fun main() {
testRunBlocking.invoke()
}
日志输出
0 --- main
1 --- main
2 --- Thread-0 14.119.104.189
3 --- main
4 --- main
Process finished with exit code 0
- runBlocking启动的协程任务会 阻断当前线程,直到该协程执行结