协程的作用

协程并不是一个新鲜概念,相信大家都有所了解,它的好处是可以极大程度的复用线程,通过让线程满载运行,达到最大程度的利用CPU,进而提升应用性能。它和反应式编程一样都可以有效的提高资源的利用率,并且让我们脱离callback hell。目前JAVA里还没有原生的协程库(AJDK里对协程提供了支持)。Kotlin从1.1开始支持协程,不过目前还处于试验阶段,感兴趣的同学可以查看这篇文档。

如何在kotlin里使用协程

launch

由于协程还处于试验阶段,没有在Kotlin的标准库里提供,因此我们需要先引入一下相关的Jar包,Maven引用如下(其它同理)

<dependency><groupId>org.jetbrains.kotlinx</groupId><artifactId>kotlinx-coroutines-core</artifactId><version>0.25.0</version>
</dependency>

然后直接上代码,先把官网上最简单的Hello world抄过来看看:

fun main(args: Array<String>) {launch { // 开启协程delay(1000L) // 阻塞协程,只能在协程里调用println("World!")  }println("Hello,") Thread.sleep(3000L) // 等待协程执行
}

运行会得到如下结果

Hello,
World!

我们发现代码后边的 println("Hello,") 先执行了,可以肯定是launchdelay搞的鬼,如果隐藏在launch后边的是线程,也能得到完全同样的效果,不过这里隐藏的是协程,它在这里和线程有着同样的表现,确是非常轻量级的异步实现。

launch是协程的启动函数,注意它本身并不是一个协程,大括号里的部分才是协程的本体,我们知道大括号内部其实是个lambda表达式,而lambda表达式会被编译成一个匿名内部类的对象,反编译一下这个匿名内部类,大概是这样的:

final class Demo1Kt$main$1 extends CoroutineImpl implements Function2 {private CoroutineScope p$;@Nullablepublic final Object doResume(@Nullable Object data, @Nullable Throwable throwable) {Object var5 = IntrinsicsKt.getCOROUTINE_SUSPENDED();switch(super.label) {case 0:if(throwable != null) {throw throwable;}CoroutineScope var3 = this.p$;super.label = 1;if(DelayKt.delay$default(1000L, (TimeUnit)null, this, 2, (Object)null) == var5) {return var5;}break;case 1:if(throwable != null) {throw throwable;}break;default:throw new IllegalStateException("call to \'resume\' before \'invoke\' with coroutine");}String var4 = "World!";System.out.println(var4);return Unit.INSTANCE;}Demo1Kt$main$1(Continuation var1) {super(2, var1);}@NotNullpublic final Continuation create(@NotNull CoroutineScope $receiver, @NotNull Continuation continuation) {Intrinsics.checkParameterIsNotNull($receiver, "$receiver");Intrinsics.checkParameterIsNotNull(continuation, "continuation");Demo1Kt$main$1 var3 = new Demo1Kt$main$1(continuation);var3.p$ = $receiver;return var3;}@Nullablepublic final Object invoke(@NotNull CoroutineScope $receiver, @NotNull Continuation continuation) {Intrinsics.checkParameterIsNotNull($receiver, "$receiver");Intrinsics.checkParameterIsNotNull(continuation, "continuation");return ((Demo1Kt$main$1)this.create((CoroutineScope)$receiver, continuation)).doResume(Unit.INSTANCE, (Throwable)null);}
}

也不知道都是什么鬼(以后再说),我们只需要知道它实现了CoroutineImpl即可,CoroutineImpl实现了Continuation接口,Continuation代表了Kotlin里的协程,协程运行,其实就是运行Continuation

我们再看下launch的定义,

public fun launch(context: CoroutineContext , start: CoroutineStart , parent: Job?, onCompletion: CompletionHandler? , block: suspend CoroutineScope.() -> Unit):Job

先忽略它的参数,看看它的返回值Job,Job最常用的方法有三个,分别是start,joincancel,cancel没啥好说的,我们看看如何使用startjob:

fun main(args: Array<String>) = runBlocking(){val job = launch(EmptyCoroutineContext,CoroutineStart.LAZY) { // 开启协程println("execuse me!")doSomeDelay()}Thread.sleep(2000)println("Hello,")job.start()job.join()
}suspend fun doSomeDelay() {delay(1000)println("World!")
}

这段代码的输出是

Hello,
execuse me!
World!

它除了调用了job的start和join方法外,还给launch传递了两个参数,引入了suspendrunBlocking两个关键字。我们一一看来:
CoroutineContext这玩意从名字看是协程上下文,我们先忽略,传个默认值,
CoroutineStart代表协程的启动方式,它是个枚举,如果它的值是LAZY,则协程不会立即启动,需要我们手工启动,这也是job.start()的意义。看输出,虽然先调用了launch方法,但是协程里的第一行代码哪怕主线程sleep了2000ms,也没有执行,而是一直等到调用start方法之后才执行。可以证明协程并没有随着launch的调用启动。

join方法,表示当前协程等待job所在的协程执行结束。它和线程里的join方法有同样的语义,大家对比着学习即可。这里需要注意的是join方法是suspend关键字修饰的,我们看下它的声明:

public abstract suspend fun join(): kotlin.Unit

一个协程方法必须被suspend修饰,且suspend修饰的方法必须在协程体里或者被suspend修饰的方法调用,比如第一段程序的代码,delay也是suspend修饰的,把delay那行放在launch外边,就会产生编译错误。这也是为什么我们把上边的代码里用了runBlocking方法。runBlocking会开启一个新的协程,并阻塞当前的线程,直到里面的代码执行完毕。

官方说法:

Runs new coroutine and blocks current thread interruptibly until its completion.

async

写到这里想必大家发现launch没法获取协程里代码的返回值,它有点像线程里的Runnable,但是很多情况下我们需要返回值,这时就需要async方法出场了,我们再来一个hello world:

fun main(args: Array<String>) = runBlocking {val deffered = async {doSomeThing()}println("Hello,")println(deffered.await())}suspend fun doSomeThing(): String {delay(1000)return "world!"
}

它的输出如下:

Hello,
world!

Deferred继承了Job,它除了拥有Job的方法外,还有一个await方法,它也是被suspend修饰的方法,因此我们在runBlocking里调用它。其它方面基本都和launch以及Job大同小异,就不赘述了。

总结

我们回顾一下,这里讲了

  1. 启动无返回值协程的launch方法和它的返回值Job,可以把它理解成线程里的Runnable
  2. 有返回值协程的async方法和它的返回值Deferred,可以把它理解成线程里的Callable
  3. 声明协程的关键字suspend
  4. 阻塞执行的runBlocking

有了这些,我们已经基本可以用协程实现功能了,更高级的东西下篇再说。

参考文献

https://kymjs.com/code/2017/11/24/01/
https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md#composing-suspending-functions
http://kotlinlang.org/docs/reference/coroutines.html#experimental-status-of-coroutines
https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/run-blocking.html

AD Time

国际惯例,给我们的读书群[独来读往]打个广告。欢迎喜欢读书的小伙伴加入我们,一起交流,一起成长.详见
https://lark.alipay.com/growth/notes/ewqntu

好久没打广告了o( ̄︶ ̄)o

Kotlin协程简介(一) Hello,coroutines!相关推荐

  1. Kotlin协程简介

    1.  什么是协程 关于协程的定义有很多,在Kotlin语言中,协程比较合理的定义应该是一个线程框架(扔物线)或者说是一种并发设计模式(官方).它是由官方设计的一套API方便开发者进行多线程开发. 2 ...

  2. Kotlin协程简介(一)

    目录: 一. 协程的基本概念 二. 从异步编程开始 回调 CompletableFuture RxJava 协程 三. 协程的基本概念 suspend funtion CoroutineScope C ...

  3. kotlin协程简单封装,助你一臂之力

    简述 经过两天的学习历程,看遍了国内的经典博客,也看完了官方的文档.下面推荐大家阅读 好的文章: 开始使用Kotlin协程 官方: kotlinx.coroutines 如果英文够好,推荐看官网的,例 ...

  4. kotlin协程_使Kotlin协程无缝采用的5个技巧

    kotlin协程 After successfully adopting coroutines in my prod project I think it is time to share 5 tip ...

  5. 探索 Kotlin 协程原理

    接下来跟大家分享一下我在了解 Kotlin 协程实现的过程中理解的一些概念,如果你发现哪些地方我说错了的话,欢迎提出你的理解. 1. Kotlin 协程原理概述 Kotlin 协程的大致的执行流程如上 ...

  6. Android中使用Kotlin协程(Coroutines)和Retrofit进行网络请求(二)之文件下载

    写在前面 下载功能是非常常用的功能,今天我们要通过kotlin协程和retrofit来是实现文件下载的功能.retorfit本身可以将请求结果以InputStream的形式返回,拿到InputStre ...

  7. 在 Android 开发中使用 Kotlin 协程 (一) -- 初识 Kotlin 协程

    前言 最近在研究 Kotlin 协程,发现功能真的超级强大,很有用,而且很好学,如果你正在或计划使用 Kotlin 开发 Android,那么 Kotlin 协程你一定不能错过! 协程是什么? 我们平 ...

  8. 动手实现Kotlin协程同步切换线程,以及Kotlin协程是如何实现线程切换的

    前言 突发奇想想搞一个同步切换线程的Kotlin协程,而不用各种withContext(){},可以减少嵌套且逻辑更清晰,想实现的结果如下图: 分析 实现我们想要的结果,首先需要知道协程为什么可以控制 ...

  9. Kotlin 协程 + Spring webflux 开发后端

    前言 后端响应式是未来,吞吐量会更大,而资源占用更少,其用到了类似Android系统的Loop(事件循环)机制,而协程可以减少线程等待的消耗,并且同步式的编程方式使代码可读性更高,两个仿佛天生就是一对 ...

最新文章

  1. 学好机器学习必备这12条经验 !(附资料)
  2. 【干货】2020史上最全自动驾驶资源大合集!
  3. 解决 Virtual PC 在 XP PAE模式下无法运行的问题
  4. 从零开始的自学之路——css选择器
  5. 第77课 交作业啦(递归算法)
  6. [C++] Pure Virtual Function and Abstract Class
  7. swt matlab 中 swa,Matlab小波工具箱的使用3
  8. java double 值是6.346255785955615E-4,这是字母“E”什么意思
  9. 自适应滤波器5-最小二乘法(LSM)
  10. android sd卡数据恢复软件下载,手机SD卡内存卡数据恢复软件
  11. “死”法不重样,一根数据线如何从“机器伴侣”变身电脑杀手?
  12. 生日快乐程序_时光匆匆,爱你不变——祝星广十七岁生日快乐
  13. MacOS连接VPN 提醒 “IPSec共享密钥”丢失。请验证您的设置并尝试重新连接。
  14. 一个08届毕业的学长写给即将毕业的09届的学弟学妹们
  15. 设备故障率高的四大原因及对策分析
  16. Google Earth Engine(GEE)对比显示不同城市的地表温度
  17. postman如何测试导入任务和导出任务
  18. MySql 查重、去重的实现
  19. 湖北省制造业高质量发展专项奖励申报条件,2022年揭榜挂帅项目指南
  20. 31省市招生考试院网址汇总!招生变化早知道!

热门文章

  1. 使用webuploader组件实现大文件分片上传,断点续传
  2. 浅析GitLab Flow的十一个规则
  3. 十个Android Material Design库
  4. 《HBase企业应用开发实战》—— 3.6 本章小结
  5. Linux内核邮件列表发送和回复格式研究
  6. MySQL内存及虚拟内存优化设置
  7. [React Native Android 安利系列]样式与布局的书写
  8. python的urllib2包基本使用方法
  9. L101 L201 ME35 ME350 SX235W EP-801A ME535 清零软件
  10. 他在 Stack Overflow 提问如何黑掉Stack Overflow,结果成了