Android面试题

Android面试题之Kotlin协程一文搞定

2024-05-06  本文已影响0人  AntDream
定义

协程基于线程,是轻量级的线程

作用
特点
挂起函数
挂起和阻塞的区别
协程调度器
任务泄漏
结构化并发
协程作用域CoroutineScope
协程构建器

launch和async构建器都用来启动新协程

构建器 是否立即启动? 串行?并行? 是否阻塞当前线程? 返回结果
launch 根据包裹的子协程类型而定 Job对象
async 任务之间是并行 Deferred,可以用await()方法获取结果
runBlocking 根据包裹的子协程类型而定 阻塞 子协程都执行完毕后才退出
withContext 不是 任务之间是串行 可以直接返回耗时任务结果,协程体最后一行内容
doAsync和async
btn.setOnClickListener {
    doAsync {
        Log.e("TAG", " doAsync...   [当前线程为:${Thread.currentThread().name}]")
        uiThread {
            Log.e("TAG", " uiThread....   [当前线程为:${Thread.currentThread().name}]")
        }
    }
}
Job对象的生命周期
等待一个作业

由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是在主线程中
协程作用域构建器 coroutineScope、runBlocking、supervisorScope
协程作用域构建器 coroutineScope、supervisorScope
coroutineScope和CoroutineScope
协程的取消
CPU密集型任务的取消
协程取消的副作用
@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")
}
上一篇 下一篇

猜你喜欢

热点阅读