Kotlin协程(2)✔️创建协程

2019-06-20  本文已影响0人  狼性代码人
  • kotlin 协程 API
  • 创建支持 kotlinx.coroutines 的项目
  • 第一个协程程序
  • launch 函数
  • Job 对象
  • runBlocking 函数
  • 挂起函数

kotlin 协程 API

Kotlin 支持协程,并提供了丰富的协程编程所需的 API,主要是三个方面的支持:
(1) 语言支持。kotlin 语言本身提供一些对协程的支持,例如 kotlin 中的 suspend 关键字可以声明一个挂起函数。
(2) 底层 API。kotlin 标准库中包含协程编程核心底层 API,来自于 kotlin. coroutines 包,这些底层 API 虽然也可以编写携程代码,但是使用起来非常麻烦,不推荐直接使用这些底层 API。
(3) 高级 API。高级 API 使用起来很简单,但 kotlin 标准库中没有高级 API,它来自于 kotlin 的扩展项目 kotlinx.coroutines 框架(https://github.com/Kotlin/kotlinx.coroutines),使用时需要额外配置项目依赖关系。

创建支持 kotlinx.coroutines 的项目

  kotlinx.coroutines 提供了协程开发的高级 API,使用起来比标准库中的底层 API 要简单得多。但使用 kotlinx.coroutines需要额外在项目中配置依赖关系。下面是在 build.gradle 文件中添加 kotlinx.coroutines 依赖关系的配置。

apply plugin: 'java-library'
apply plugin: 'kotlin'

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinx_coroutines" // 1️⃣
}

sourceCompatibility = "8"
targetCompatibility = "8"

buildscript {
    ext.kotlin_version = '1.3.31' // 2️⃣
    ext.kotlinx_coroutines = '1.3.0-M1'
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

repositories {
    mavenCentral()
}

compileKotlin {
    kotlinOptions {
        jvmTarget = "1.8"
    }
}

compileTestKotlin {
    kotlinOptions {
        jvmTarget = "1.8"
    }
}

  上述代码第1️⃣行的 implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinx_coroutines" 是刚刚添加的依赖关系。另外,还需要检测代码第2️⃣行的 ext.kotlin_version 是否为最新的 kotlin 版本。

第一个协程程序

  协程是轻量级的线程,因此协程也是由主线程管理的,如果主线程结束那么协程也就结束了。

fun main(args: Array<String>?) {
    GlobalScope.launch { // 1️⃣
        for (i in 1..10) {
            println("子协程执行第${i}次")
            val sleepTime = (random() * 1000).toLong()
            delay(sleepTime) // 2️⃣
        }
        println("子协程执行结束")
    }
    sleep(10 * 1000) // 3️⃣
    println("主程序结束...")
}

运行结果:

子协程执行第1次
子协程执行第2次
子协程执行第3次
子协程执行第4次
子协程执行第5次
子协程执行第6次
子协程执行第7次
子协程执行第8次
子协程执行第9次
子协程执行第10次
子协程执行结束
主程序结束...

  上述代码第1️⃣行的 GlobalScope.launch 函数创建并启动了一个协程,类似于线程的 thread 函数。代码第2️⃣行的 delay 函数是挂起协程,类似于线程的 sleep 函数,但不同的是 delay 函数不会阻塞线程,而 sleep 函数会阻塞线程。代码第3️⃣行时候让主线程休眠 10s。如果这里主线程不休眠,主线程就直接结束了,其他的线程或协程没有机会运行。

launch 函数

  上面示例中的 GlobalScope.launch 函数是非常重要的,它的定义如下:

public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job

Job 对象

Job 对象中常用的属性和函数如下:

fun main(args: Array<String>?) {
    val job = GlobalScope.launch {
        for (i in 1..10) {
            println("子协程执行第${i}次")
            val sleepTime = (random() * 1000).toLong()
            delay(sleepTime)
        }
        println("子协程执行结束")
    }
    println(job.isActive)
    println(job.isCompleted)
    sleep(10 * 1000)
    println("主程序结束...")
    println(job.isCompleted)
}
// 运行结果:
true
false
子协程执行第1次
子协程执行第2次
子协程执行第3次
子协程执行第4次
子协程执行第5次
子协程执行第6次
子协程执行第7次
子协程执行第8次
子协程执行第9次
子协程执行第10次
子协程执行结束
主程序结束...
true

runBlocking 函数

  前面的例子为了保持其他线程处于活动状态,示例中都使用了 sleep 函数。sleep 函数是线程提供的函数,最好不要在协程中使用,应该使用协程自己的 delay 函数,但 delay 是挂起函数,必须在协程体 或 其他的挂起函数中使用。

fun main(args: Array<String>?) = runBlocking {
    GlobalScope.launch {
        for (i in 1..10) {
            println("子协程执行第${i}次")
            val sleepTime = (random() * 1000).toLong()
            delay(sleepTime)
        }
        println("子协程执行结束")
    }
    delay(10 * 1000) // 1️⃣
    println("主程序结束...")
}
// 运行结果
子协程执行第1次
子协程执行第2次
子协程执行第3次
子协程执行第4次
子协程执行第5次
子协程执行第6次
子协程执行第7次
子协程执行第8次
子协程执行第9次
子协程执行第10次
子协程执行结束
主程序结束...

  上述代码将 main 代码放到 runBlocking 函数中,runBlocking 函数也是启动并创建一个协程,可以与顶层函数一起使用。代码第1️⃣行使用 delay 函数挂起主协程。

挂起函数

  如果开发人员需要编写一个挂起函数,可以使用 suspend 关键字声明,语法如下:

suspend fun 函数名(参数列表): 返回类型 {
    // 函数体
}

  注意:挂起函数只能在协程体中 或 其他的挂起函数中调用,不能在普通函数中调用。

  挂起函数不仅可以是顶层函数,还可以是成员函数和抽象函数,子类重写挂起函数后还应该是挂起的。

abstract class SuperClass {
    suspend abstract fun run()
}

class SubClass: SuperClass() {
    override suspend fun run() { }
}

  上述代码 SubClass 类实现了抽象类 SuperClass 的抽象挂起函数 run,重写后它还是挂起函数。

fun main(args: Array<String>?) = runBlocking {
    GlobalScope.launch {
        run("job1")
    }
    GlobalScope.launch {
        run("job2")
    }
    delay(10 * 1000)
    println("主程序结束...")
}

suspend fun run(name:String) {
    for (i in 1..10) {
        println("子协程 ${name} 执行第${i}次")
        val sleepTime = (random() * 1000).toLong()
        delay(sleepTime)
    }
    println("子协程 ${name} 执行结束")
}
// 运行结果
子协程 job1 执行第1次
子协程 job2 执行第1次
子协程 job1 执行第2次
子协程 job1 执行第3次
子协程 job1 执行第4次
子协程 job2 执行第2次
子协程 job2 执行第3次
子协程 job1 执行第5次
子协程 job1 执行第6次
子协程 job1 执行第7次
子协程 job2 执行第4次
子协程 job2 执行第5次
子协程 job2 执行第6次
子协程 job1 执行第8次
子协程 job1 执行第9次
子协程 job2 执行第7次
子协程 job2 执行第8次
子协程 job1 执行第10次
子协程 job1 执行结束
子协程 job2 执行第9次
子协程 job2 执行第10次
子协程 job2 执行结束
主程序结束...
上一篇下一篇

猜你喜欢

热点阅读