浅析kotlin协程

516 阅读3分钟

首先协程是轻量级的线程

协程创建方式

1.GlobalScope.launch

GlobalScope.launch(Dispatchers.Main) {
    println("")
}

这函数创建了一个协程的作用域,Lambda表达式就在协程中运行了,这个函数创建的是一个顶层协程,这种协程当程序运行结束也结束,你会发现执行后日志不会打印,因为还没有来得及执行代码块中的代码执行,程序就结束了。

2.delay

GlobalScope.launch{
    println("")
    delay(1000)
}

这个时候加一个延时就行了,delay函数是一个非阻塞的挂起函数,delay函数会挂起当前协程,当不会影响其他协程 这里相信大家一定想到了Thread,sleep()函数,但Thread,sleep()函数会阻塞当前线程,这样线程下的所有协程也会被阻塞。

3.runBlocking

runBlocking { println("") delay(1000) }

runBlocking {
    println("")
    delay(1000)
}

此函数也创建了一个协程的作用域,但它可以保证协程中所有代码执行完之前一直阻塞当前线程,但只建议测试使用。

4.launch

runBlocking {
    launch{
    println("")
    delay(1000)
    }
    launch{
    println("")
    delay(1000)
    }
}

此函数只能在协程的作用域中使用,然后再当前协程的作用域下创建子协程,如果外层协程结束,那此作用域下的所有协程都会结束。

5.suspend

suspend fun printDelay() {
    println("")
    delay(1000)
}

用于将部分代码封装到一个方法中,声明为挂起函数,挂起函数间可以相互调用,但是无法提供协程作用域。

6.coroutineScope

suspend fun printDelay()=coroutineScope {
    launch{
    println("")
    delay(1000)
    }
}

首先coroutineScope也是一个挂起函数,而且会继承外部的协程作用域并创建一个子协程,这样我们就解决了上面的问题,而且它和runBlocking一样可以保证协程中所有代码执行完。

7.取消协程

val job=GlobalScope.launch{
    println("")
    delay(1000)
}
job.cancel()

其实launch函数返回了一个Job对象,调用cancel函数可取消协程。

8.获取返回结果

runBlocking {
    println("")
    val result=async{
    6*2
    }.await()
    delay(1000)
}

async函数可以创建一个子协程并返回一个Deferred对象,如果想获取aa=sync函数代码块中的执行结果,就调用Deferred对象的await函数,当调用await函数时,如果代码没有执行完,就会阻塞当前协程。

9.并行获取返回结果

runBlocking {
    println("")
    val result=async{
    6*2
    }
    val result1=async{
    6+8
    }
    Log.i("","result is ${result.await()+result1.await()}")
    delay(1000)
}

在最后调用2个async函数的await函数,就变成了并发执行关系。

10.withContext

runBlocking {
    val result=withContext(Dispatchers.Default){
    6*2
    }
    delay(1000)
}

类似async函数,会马上执行代码块的代码,同时挂起外部协程。当代码块代码执行完后,会返回最后一行代码作为返回值。 与async函数不同的是,withContext要求强制输入一个线程参数。 这个参数有三个可以选择 (1)Dispatchers.Default 表示默认低并发的线程策略,适合计算密集型的任务 (2)Dispatchers.IO 表示较高并发线程策略,适合执行的代码大多数时间都在阻塞和等待中,比如网络请求 (3)Dispatchers.Main 表示不会开启子线程,而在主线程中执行代码,只能在Android代码中可以使用

11.线程参数 其实除了coroutineScope函数之外,其他函数都可以指定一个线程参数,只是withContext要求强制输入一个线程参数。