第20章 协程
上一章介绍了线程,本章介绍的协程与线程类似都可以处理并发任务。协程在很多语言中都支持,但Java没有协程支持,Kotlin支持协程编程。本章介绍协程。
20.1 协程介绍
协程(Coroutines)是一种轻量级的线程,协程提供了一种不阻塞线程,但是可以被挂起的计算过程。线程阻塞开销是巨大的,而协程挂起基本上没有开销。
在执行阻塞任务时,会将这种任务放到子线程中执行,执行完成再回调(callback)主线程,更新UI等操作,这就是异步编程。协程底层库也是异步处理阻塞任务,但是这些复杂的操作被底层库封装起来,协程代码的程序流是顺序的,不再需要一堆的回调函数,就像同步代码一样,也便于理解、调试和开发。
线程是抢占式的,线程调度是操作系统级的。而协程是协作式的,而协程调度是用户级的,协程是用户空间线程,与操作系统无关,所以需要用户自己去做调度。
20.2 创建协程
这一节介绍Kotlin中任何编写协程程序。
20.1.1 Kotlin协程API
Kotlin支持协程,通过了丰富的协程编程所需的API,主要是三个方面的支持:
1.语言支持。Kotlin语言本身提供一些对协程的支持,例如Kotlin中的suspend关键字可以声明一个挂起函数。
2.底层API。Kotlin标准库中包含协程编程核心底层API,来自于kotlin.coroutines.experimental包,这些底层API虽然也可以编写协程代码,但是使用起来非常麻烦,笔者不推荐直接使用这些底层API。
3.高级API。高级API使用起来很简单,但Kotlin标准库中没有高级API,它来自于Kotlin的扩展项目kotlinx.coroutines框架(https://github.com/Kotlin/kotlinx.coroutines),使用时需要额外配置项目依赖关系。kotlinx.coroutines包名是kotlinx.coroutines.experimental。
20.2.2 创建支持kotlinx.coroutines项目
由于kotlinx.coroutines提供了高级API,使用起来较标准库中底层API要简单的多。本书重点介绍使用kotlinx.coroutines实现协程编程。kotlinx.coroutines不属于Kotlin标准库,需要额外配置项目依赖关系,因此需要创建IntelliJ IDEA+Gradle项目,项目创建完成后在打开build.gradle文件,添加依赖关系,具体内容如下:
group ‘com.51work6’
version ‘1.0-SNAPSHOT’
apply plugin: ‘java’
apply plugin: ‘kotlin’
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile “org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version”
compile ‘org.jetbrains.kotlinx:kotlinx-coroutines-core:0.19.3’ ①
testCompile group: ‘junit’, name:‘junit’, version: ‘4.12’
}
compileKotlin {
kotlinOptions.jvmTarget =“1.8”
}
compileTestKotlin {
kotlinOptions.jvmTarget =“1.8”
}
group ‘com.51work6’
version ‘1.0-SNAPSHOT’
buildscript {
ext.kotlin_version = ‘1.1.51’ ②
repositories {
mavenCentral()
}
dependencies {
classpath"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
上述代码第①行compile 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.19.3’是刚刚添加的依赖关系。另外,还需要检查代码第②行的ext.kotlin_version是否是最新Kotlin版本。
20.2.3 第一个协程程序
协程是轻量级的线程,因此协程也是由主线程管理的,如果主线程结束那么协程也就结束了。下面看看第一个协程示例:
//代码文件:chapter20/src/main/kotlin/com/a51work6/section2/ch20.2.3.kt
package com.a51work6.section2
import kotlinx.coroutines.experimental.delay
import kotlinx.coroutines.experimental.launch
import java.lang.Math.random
import java.lang.Thread.sleep
fun main(args: Array) {