Kotlin协程简介(一) Hello,coroutines!
协程的作用
协程并不是一个新鲜概念,相信大家都有所了解,它的好处是可以极大程度的复用线程,通过让线程满载运行,达到最大程度的利用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,")
先执行了,可以肯定是launch
和delay
搞的鬼,如果隐藏在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
,join
和cancel
,cancel
没啥好说的,我们看看如何使用start
和job
:
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
传递了两个参数,引入了suspend
和runBlocking
两个关键字。我们一一看来:
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
大同小异,就不赘述了。
总结
我们回顾一下,这里讲了
- 启动无返回值协程的
launch
方法和它的返回值Job
,可以把它理解成线程里的Runnable
- 有返回值协程的
async
方法和它的返回值Deferred
,可以把它理解成线程里的Callable
- 声明协程的关键字
suspend
- 阻塞执行的
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!相关推荐
- Kotlin协程简介
1. 什么是协程 关于协程的定义有很多,在Kotlin语言中,协程比较合理的定义应该是一个线程框架(扔物线)或者说是一种并发设计模式(官方).它是由官方设计的一套API方便开发者进行多线程开发. 2 ...
- Kotlin协程简介(一)
目录: 一. 协程的基本概念 二. 从异步编程开始 回调 CompletableFuture RxJava 协程 三. 协程的基本概念 suspend funtion CoroutineScope C ...
- kotlin协程简单封装,助你一臂之力
简述 经过两天的学习历程,看遍了国内的经典博客,也看完了官方的文档.下面推荐大家阅读 好的文章: 开始使用Kotlin协程 官方: kotlinx.coroutines 如果英文够好,推荐看官网的,例 ...
- kotlin协程_使Kotlin协程无缝采用的5个技巧
kotlin协程 After successfully adopting coroutines in my prod project I think it is time to share 5 tip ...
- 探索 Kotlin 协程原理
接下来跟大家分享一下我在了解 Kotlin 协程实现的过程中理解的一些概念,如果你发现哪些地方我说错了的话,欢迎提出你的理解. 1. Kotlin 协程原理概述 Kotlin 协程的大致的执行流程如上 ...
- Android中使用Kotlin协程(Coroutines)和Retrofit进行网络请求(二)之文件下载
写在前面 下载功能是非常常用的功能,今天我们要通过kotlin协程和retrofit来是实现文件下载的功能.retorfit本身可以将请求结果以InputStream的形式返回,拿到InputStre ...
- 在 Android 开发中使用 Kotlin 协程 (一) -- 初识 Kotlin 协程
前言 最近在研究 Kotlin 协程,发现功能真的超级强大,很有用,而且很好学,如果你正在或计划使用 Kotlin 开发 Android,那么 Kotlin 协程你一定不能错过! 协程是什么? 我们平 ...
- 动手实现Kotlin协程同步切换线程,以及Kotlin协程是如何实现线程切换的
前言 突发奇想想搞一个同步切换线程的Kotlin协程,而不用各种withContext(){},可以减少嵌套且逻辑更清晰,想实现的结果如下图: 分析 实现我们想要的结果,首先需要知道协程为什么可以控制 ...
- Kotlin 协程 + Spring webflux 开发后端
前言 后端响应式是未来,吞吐量会更大,而资源占用更少,其用到了类似Android系统的Loop(事件循环)机制,而协程可以减少线程等待的消耗,并且同步式的编程方式使代码可读性更高,两个仿佛天生就是一对 ...
最新文章
- 学好机器学习必备这12条经验 !(附资料)
- 【干货】2020史上最全自动驾驶资源大合集!
- 解决 Virtual PC 在 XP PAE模式下无法运行的问题
- 从零开始的自学之路——css选择器
- 第77课 交作业啦(递归算法)
- [C++] Pure Virtual Function and Abstract Class
- swt matlab 中 swa,Matlab小波工具箱的使用3
- java double 值是6.346255785955615E-4,这是字母“E”什么意思
- 自适应滤波器5-最小二乘法(LSM)
- android sd卡数据恢复软件下载,手机SD卡内存卡数据恢复软件
- “死”法不重样,一根数据线如何从“机器伴侣”变身电脑杀手?
- 生日快乐程序_时光匆匆,爱你不变——祝星广十七岁生日快乐
- MacOS连接VPN 提醒 “IPSec共享密钥”丢失。请验证您的设置并尝试重新连接。
- 一个08届毕业的学长写给即将毕业的09届的学弟学妹们
- 设备故障率高的四大原因及对策分析
- Google Earth Engine(GEE)对比显示不同城市的地表温度
- postman如何测试导入任务和导出任务
- MySql 查重、去重的实现
- 湖北省制造业高质量发展专项奖励申报条件,2022年揭榜挂帅项目指南
- 31省市招生考试院网址汇总!招生变化早知道!
热门文章
- 使用webuploader组件实现大文件分片上传,断点续传
- 浅析GitLab Flow的十一个规则
- 十个Android Material Design库
- 《HBase企业应用开发实战》—— 3.6 本章小结
- Linux内核邮件列表发送和回复格式研究
- MySQL内存及虚拟内存优化设置
- [React Native Android 安利系列]样式与布局的书写
- python的urllib2包基本使用方法
- L101 L201 ME35 ME350 SX235W EP-801A ME535 清零软件
- 他在 Stack Overflow 提问如何黑掉Stack Overflow,结果成了