本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点
协程基于线程,是轻量级的线程
launch和async构建器都用来启动新协程
构建器 | 是否立即启动? | 串行?并行? | 是否阻塞当前线程? | 返回结果 |
---|---|---|---|---|
launch | 是 | 根据包裹的子协程类型而定 | 否 | Job对象 |
async | 是 | 任务之间是并行 | 否 | Deferred,可以用await()方法获取结果 |
runBlocking | 是 | 根据包裹的子协程类型而定 | 阻塞 | 子协程都执行完毕后才退出 |
withContext | 不是 | 任务之间是串行 | 否 | 可以直接返回耗时任务结果,协程体最后一行内容 |
btn.setOnClickListener {
doAsync {
Log.e("TAG", " doAsync... [当前线程为:${Thread.currentThread().name}]")
uiThread {
Log.e("TAG", " uiThread.... [当前线程为:${Thread.currentThread().name}]")
}
}
}
由launch启动的协程用join()方法;用async启动的协程用await()
@Test
fun `test coroutine join`() = runBlocking {
val job1 = launch {
delay(200)
println("job1 finished")
}
//这样可以确保job1执行完再执行后面的job2和job3
job1.join()
val job2 = launch {
delay(200)
println("job2 finished")
//返回结果
"job2 result"
}
val job3 = launch {
delay(200)
println("job3 finished")
//返回结果
"job2 result"
}
}
@Test
fun `test async`() = runBlocking {
val time = measureTimeMillis {
val one = doOne()
val two = doTwo()
//输出是30
println("result: ${one + two}")
}
//输出是2秒多,也就是是串行的
println(time)
}
//并发
@Test
fun `test combine async`() = runBlocking {
val time = measureTimeMillis {
val one = async { doOne() }
val two = async { doTwo() }
//输出是30
println("result: ${one.await() + two.await()}")
}
//输出是1秒多,也就是是并行的
println(time)
}
private suspend fun doOne(): Int{
delay(1000)
return 10
}
private suspend fun doTwo(): Int{
delay(1000)
return 20
}
注意async的写法不能是:
val one = async { doOne() }.await()
val two = async { doTwo() }.await()
这样起不到并发效果,而是等到one执行完,再执行two
需要注意的是,立即调度不等于立即执行
@Test
fun `test start mode`() = runBlocking {
val job = async(start = CoroutineStart.LAZY) {
//
}
//...其他代码
//启动协程
job.await()
}
@Test
fun `test start mode`() = runBlocking {
val job = async(context = Dispatchers.IO, start = CoroutineStart.UNDISPATCHED) {
println("thread:"+ Thread.currentThread().name)
}
}
//上面输出的线程名字是主线程,因为UNDISPATCHED会立即在当前线程中执行,而runBlocking是在主线程中
@Test
fun `test release resources`() = runBlocking {
var br = BufferedReader(FileReader("xxx"))
with(br){
var line:String?
try {
while (true){
line = readLine() ?: break
println(line)
}
}finally {
//关闭资源
close()
}
}
}
//use函数在文件使用完毕后会自动调用close函数
BufferedReader(FileReader("xxx")).use {
var line:String?
while (true){
line = readLine() ?: break
println(line)
}
}
协程被取消后,finally里面还有挂起函数,可以用withContext(NonCancellable)
@Test
fun `test cancel with noncancellable`() = runBlocking {
val job = launch {
try {
repeat(1000){
println("job: i'm sleeping $it")
delay(500L)
}
}finally {
//不用withContext(NonCancellable),delay后面的打印不会执行
withContext(NonCancellable){
println("running finally")
delay(1000L)
println("job: noncancellable")
}
}
}
delay(1300)
println("main: waiting")
job.cancelAndJoin()
println("main: i can quit")
}
withTimeout()方法可以开启超时任务,默认超时会抛出异常
/*
* 超时任务
* */
@Test
fun `test deal with timeout`() = runBlocking {
withTimeout(1300){
repeat(1000){
println("job: sleeping $it")
delay(500L)
}
}
}
如果不想抛出异常,可以用withTimeoutOrNull
/*
* 超时任务,超时会返回null,不超时返回最后的done
* */
@Test
fun `test deal with timeout ornull`() = runBlocking {
val result = withTimeoutOrNull(1300){
repeat(1000){
println("job: sleeping $it")
delay(500L)
}
"done"
}
println("result: $result")
}