美文网首页
Kotlin协程

Kotlin协程

作者: 橙子6193 | 来源:发表于2022-03-04 20:58 被阅读0次

    1、协程的概念

    相当于轻量级线程,线程的切换需要操作系统进行调度,而协程在编译语言层面就能实现自由切换,开销比线程要小的多,这种特性使得高并发程序的执行效率得到了极大的提升

    2、协程的优点

    可控制、开销小、语法糖(减少回调,已同步的写法代替之前异步的写法)
    协程与线程是属于一个层级的,但是却又和线程处理并行任务有着不同的解决方案,协程可以在处理完并发任务之后,自动切回UI(mian/主)线程;线程处理完并发任务默认是不会直接切回UI(mian/主)线程,需要我们手动去切回UI(mian/主)线程,因此,协程不仅切换成本小,还可以避免回调地狱

    3、协程的用法

    首先引入依赖

    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1"
    

    GlobalScope.launch

    class ExampleUnitTest {
        @Test
        fun addition_isCorrect() {
            GlobalScope.launch {
                delay(1500)
                println("codes run in coroutine scope")
            }
            sleep(1000)
        }
    }
    

    GlobalScope.launch创建的协程是顶层协程,返回值时Job,会随着线程的销毁而销毁,因此需要sleep 1s,delay只能用于协程作用域或挂起函数里,delay在协程中调用时只会阻塞当前协程,不会影响其它协程

    runBlocking

    class ExampleUnitTest {
        @Test
        fun addition_isCorrect() {
            runBlocking {
                launch {
                    delay(1000)
                    println("codes run in runblocking")
                }
            }
        }
    }
    

    runBlocking 可以阻塞当前线程直到其中的所有协程全部执行完成,一般在测试环境使用

    挂起函数和coroutineScope

    当协程内代码过多时,我们可以把其中一部分代码抽出来写成一个方法,但如果需要在方法中使用delay方法时,需要把这个方法声明成挂起函数,用suspend修饰,不过现在还是不能使用launch,因为挂起函数不是协程作用域,如果想在挂起函数中使用launch方法,可以用coroutineScope函数使挂起函数拥有协程作用域,如下:

    //挂起函数中使用delay方法
    suspend fun method1(){
            delay(1000)
            println("test  fdfda")
        }
    //使用coroutineScope声明一个带协程作用域的方法
    suspend fun method2()= coroutineScope{
            launch {
                println("method2")
            }
        }
    

    coroutineScope会阻塞当前协程,直到它内部的所有协程都执行完
    在实际项目中,由于runBlocking可能会阻塞当前线程,一般不用,而Global.launch这种顶层协程每个会返回一个Job,管理起来比较麻烦,所以一般也不使用,下面介绍一种项目中常用的协程使用

            val job=Job()
            val scope= CoroutineScope(job)
            scope.launch {
                println("111111")
                delay(100)
                println("111111")
            }
            scope.launch {
                println("22222")
                delay(100)
                println("22222")
            }
            //job.cancel()
            sleep(1000)
    

    使用Job可统一取消所有通过CoroutineScope启动的协程(这种和顶层协程一样,不会阻塞线程,随线程销毁而结束),因为launch函数只能返回job对象,那么如果我们需要获取一个协程的返回结果时,就得使用async函数了

    能获取协程结果的async函数

    async必须在协程作用域才能调用,它会创建一个新的协程并返回一个Deferred对象,调用Deferred对象的await方法即可获取协程的结果,如下:

    //能获取协程结果的async函数
            runBlocking {
                val result=async {
                    5+6
                }.await()
                println(result)
            }
    //await会阻塞当前协程(不影响其它协程),直到可以获取到async的结果
            runBlocking {
                val result=async {
                    sleep(1000)
                    println("第一个async函数")
                    5+6
                }.await()
                async {
                    println("第二个async函数")
                }.await()
                println(result)
            }
    //async函数同时执行
            runBlocking {
                val start=System.currentTimeMillis()
                val deferred1=async {
                    delay(1000)
                    println("第一个async函数")
                }
                val deferred2=async {
                    delay(1000)
                    println("第二个async函数")
                }
                deferred1.await()
                deferred2.await()
                println(System.currentTimeMillis()-start)
    

    强制要求指定线程参数的协程

           //强制要求指定线程的协程
            runBlocking {
                withContext(Dispatchers.Default){
                    delay(1000)
                    println("withContext"+Thread.currentThread().id)
                }
            }
            println("主线程id=${Thread.currentThread().id}")
    

    共有三种类型,分别是Dispatchers.Default(适用于低并发)、Dispatchers.IO(适用于高并发)、Dispatchers.Main(不会开启子线程,会在主线程执行)

    协程简化回调

        //常见的网络请求回调
        HttpUtil.sendHttpRequest(url,object:HttpCallbackListener{
            override fun onFinish(response:String){
                //得到服务器返回的具体内容
            }
            override fun onError(e:Exception){
                //异常情况处理
            }
        })
        //使用协程简化回调
        suspend fun request(url:String):String{
            return suspendCoroutine { continuation ->
                HttpUtil.sendHttpRequest(url,object:HttpCallbackListener{
                    override fun onFinish(response:String){
                        //得到服务器返回的具体内容
                        continuation.resume(response)
                    }
                    override fun onError(e:Exception){
                        //异常情况处理
                        continuation.resumeWithException(e)
                    }
                })
            }
        }
        //后续网络请求可直接这么写
        try{
            val response=request("xxxx")
            //对服务器响应的数据进行处理
        }catch(e:Exception){
            //对异常情况进行处理
        }
    

    4、协程的原理

    相关文章

      网友评论

          本文标题:Kotlin协程

          本文链接:https://www.haomeiwen.com/subject/kalmrrtx.html