关于android:Kotlin语言基础入门到熟悉Kotlin协程基础

1. 阻塞与非阻塞

runBlocking

delay是非阻塞的,Thread.sleep是阻塞的。显式应用 runBlocking 协程构建器来阻塞。

import kotlinx.coroutines.*
​
fun main() {
 GlobalScope.launch { // 在后盾启动一个新的协程并持续
 delay(200)
 "rustfisher.com".forEach {
 print(it)
 delay(280)
 }
 }
 println("主线程中的代码会立刻执行")
 runBlocking {     // 这个表达式阻塞了主线程
 delay(3000L)  //阻塞主线程避免过快退出
 }
 println("\n示例完结")
}

能够看到,runBlocking里应用了delay来提早。用了runBlocking的主线程会始终阻塞直到runBlocking外部的协程执行结束。 也就是runBlocking{ delay }实现了阻塞的成果。

咱们也能够用runBlocking来包装主函数。

import kotlinx.coroutines.*
​
fun main() = runBlocking {
 delay(100) // 在这里能够用delay了
​
 GlobalScope.launch {
 delay(100)
 println("Fisher")
 }
 print("Rust ")
 delay(3000)
}

runBlocking<Unit>中的<Unit>目前能够省略。

runBlocking也可用在测试中

// 引入junit
dependencies {
 implementation("junit:junit:4.13.1")
}

单元测试

应用@Test设置测试

import org.junit.Test
import kotlinx.coroutines.*
​
class C3Test {
​
 @Test
 fun test1() = runBlocking {
 println("junit测试开始 ${System.currentTimeMillis()}")
 delay(1234)
 println("junit测试完结 ${System.currentTimeMillis()}")
 }
}

运行后果

junit测试开始 1632401800686
junit测试完结 1632401801928

IDEA可能会提醒no tasks available。须要把测试选项改为IDEA,如下图。

更改设置

2. 期待

有时候须要期待协程执行结束。能够用join()办法。这个办法会暂停以后的协程,直到执行结束。须要用main() = runBlocking

import kotlinx.coroutines.*
​
fun main() = runBlocking {
 println("测试期待")
 val job1 = GlobalScope.launch {
 println("job1 start")
 delay(300)
 println("job1 done")
 }
 val job2 = GlobalScope.launch {
 println("job2 start")
 delay(800)
 println("job2 done")
 }
​
 job2.join()
 job1.join() // 期待
 println("测试完结")
}

运行log

测试期待
job1 start
job2 start
job1 done
job2 done
测试完结

3. 结构化的并发

GlobalScope.launch时,会创立一个顶层协程。它不应用主线程。新创的协程尽管轻量,但仍会耗费一些内存资源。如果遗记放弃对新启动的协程的援用,它还会持续运行。

咱们能够在代码中应用结构化并发。

示例中,咱们应用runBlocking协程构建器将main函数转换为协程。在外面(作用域)启动的协程不需显式应用join

察看上面的例子:

import kotlinx.coroutines.*
​
fun main() = runBlocking<Unit> {
 println("主线程id ${Thread.currentThread().id}")
 launch { // 在 runBlocking 作用域中启动一个新协程1
 println("协程1所在线程id ${Thread.currentThread().id}")
 delay(300)
 println("协程1执行结束")
 }
 launch { // 在 runBlocking 作用域中启动一个新协程2
 println("协程2所在线程id ${Thread.currentThread().id}")
 delay(500)
 println("协程2执行结束")
 }
 println("主线程执行结束")
}

运行log

主线程id 1
主线程执行结束
协程1所在线程id 1
协程2所在线程id 1
协程1执行结束
协程2执行结束

能够看到,不必像之前那样调用Thread.sleep或者delay让主线程期待一段时间,避免虚拟机退出。

程序会期待它所有的协程执行结束,而后真正退出。

4. 作用域构建器

应用 coroutineScope 构建器申明本人的作用域。它会创立一个协程作用域,并且会期待所有已启动子协程执行结束。

runBlockingcoroutineScope 看起来相似,因为它们都会期待其协程体以及所有子协程完结。次要区别在于:

  • runBlocking 办法会阻塞以后线程来期待,是惯例函数
  • coroutineScope 只是挂起,会开释底层线程用于其余用处,是挂起函数

上面这个示例展现了作用域构建器的特点。main是一个作用域。

import kotlinx.coroutines.*
​
fun main() = runBlocking { // this: CoroutineScope
 launch {
 delay(200L)
 println("协程1 t${Thread.currentThread().id}")
 }
​
 coroutineScope { // 创立一个协程作用域
 launch {
 delay(500L)
 println("外部协程2-1 t${Thread.currentThread().id}")
 }
​
 delay(100L)
 println("协程2 t${Thread.currentThread().id}")
 }
​
 println("主工作结束")
}

运行log

协程2 t1
协程1 t1
外部协程2-1t1
主工作结束

5. 提取函数重构

launch { …… }外部的代码块提取到独立的函数中。提取进去的函数须要 suspend 修饰符,它是挂起函数

import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
​
fun main() = runBlocking<Unit> {
 launch { r1() }
 println("DONE")
}
​
// 挂起函数
suspend fun r1() {
 delay(300)
 println("提取进去的函数")
}

log

DONE
提取进去的函数

6. 协程是轻量的

咱们后面也试过,创立十分多的协程,程序运行OK。

上面的代码能够输入很多的点

import kotlinx.coroutines.*
​
fun main() = runBlocking {
 for (t in 1..10000) {
 launch {
 delay(t * 500L)
 print(".")
 }
 }
}

7. 全局协程像守护线程

如果过程中只剩下了守护线程,那么虚构机会退出。 前文那个的例子,其实也能看到,字符没打印完程序就完结了。

GlobalScope 中启动的流动协程并不会使过程保活。它们就像守护线程。

再举一个例子

import kotlinx.coroutines.*
​
fun main() = runBlocking {
 GlobalScope.launch {
 for (i in 1..1000000) {
 delay(200)
 println("协程执行: $i")
 }
 }
​
 delay(1000)
 println("Bye~")
}

log

协程执行: 1
协程执行: 2
协程执行: 3
协程执行: 4
Bye~

kotlin 材料分享

高级Kotlin强化实战

140集 Kotlin 入门到精通全系列(我的项目开发实战)视频教程

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理