当前位置: 首页 > news >正文

Kotlin基础——异步和并发

同步和异步

  • 同步指的是一种行为:当执行IO操作的时候,在代码层面上我们需要主动去等待结果,直到结果返回
  • 阻塞指的是一种状态:当执行IO操作的时候,线程处于挂起状态,就是该线程没有执行了

故同步不是阻塞,同步也可以是非阻塞的,如在执行同步代码块时,线程可以不阻塞而是一直在后台运行

代码中一般通过和多线程和回调来实现异步非阻塞

但多线程只是看上去同时执行,底层原理是通过CPU调度来实现的,当一个线程切换到另一个线程时,通常需要

  • 保存当前线程的执行上下文
  • 载入另一个线程的执行上下文

切换线程也是需要开销的,故当线程切换很频繁时,可能会导致多线程并不优于单线程

协程Coroutine

大量回调会使代码更加复杂,且会存在多层次的回调,同时线程切换的开销不可忽略,而协程则可以避免这些问题

协程是一个无优先级的子程序调度组件,允许子程序在特定的地方挂起恢复

  • 进程包含线程,线程包含协程
  • 一个线程可以有任意多个协程
  • 某一时刻只能由一个协程在运行,多个协程分享该线程分配到的计算机资源
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.1"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1"

使用Coroutine需要导入包,如下通过launch构造了一个协程,通过delay()挂起协程,但不会阻塞线程

GlobalScope.launch {delay(1000L)println("World")
}
println("Hello, ")
Thread.sleep(2000L)

线程是由操作系统来调度的,而协程的切换可以由程序自己来控制,协程可以创建很多个,而线程是有限的

launch和runBlocking

  • delay只能在协程内部使用,用于挂起协程,不会阻塞线程
  • sleep用来阻塞线程

未避免混淆,可以使用runBlocking创建主协程,而使用launch创建子协程,从而在内部都使用delay(),但需要注意,runBlocking依旧会阻塞当前执行的线程

fun test() = runBlocking {GlobalScope.launch {delay(1000L)println("World")}println("Hello, ")delay(2000L)
}

协程声明周期和join

当执行耗时操作,但并不知道需要多久时,为使程序一直保活,可以使用join

  • 如下程序会一直等待,直到协程结束,这里的等待是非阻塞式,不会将当前线程挂起
  • suspend修饰的方法只能在协程内部或其他suspend方法中使用
fun test() = runBlocking {val job = launch {search()}println("Hello,")job.join()
}suspend fun search() {delay(1000L)println("World")
}

用同步方式写异步代码

在下面代码中,两个方法是顺序执行的

fun test() = runBlocking<Unit> {val one = searchOne()val two = searchTwo()println("search is ${one} and ${two}")
}suspend fun searchOne() {delay(3000L)println("one")
}suspend fun searchTwo() {delay(1000L)println("two")
}

打印如下

one
two
search is kotlin.Unit and kotlin.Unit

为了让其并行执行,可以使用async和await

  • 使用async相当于创建了一个子协程,会和其他子协程一样并行工作
  • async返回Deferred,是一个非阻塞可取消的future,其是一个带有结果的job,而Launch也会返回一个job但无返回值
  • future的意思是将来会返回一个结果,利用await可以等待返回值查询到之后获取出来
fun test() = runBlocking<Unit> {val one = async { searchOne() }val two = async { searchTwo() }println("search is ${one.await()} and ${two.await()}")
}

打印如下

one
two
search is kotlin.Unit and kotlin.Unit

共享资源控制

如对于下面的数据

val goods = hashMapOf<Long, Int>()
goods.put(1, 10)
goods.put(2, 15)

Synchronized

使用@Synchronized或synchronized()实现加锁

@Synchronized
fun buyGoods(id: Long) {val stock = goods.getValue(id)goods.put(id, stock - 1)
}
fun buyGoods2(id: Long) {synchronized(this) {val stock = goods.getValue(id)goods.put(id, stock - 1)}
}

Lock

var lock: Lock = ReentrantLock()
fun buyGoods3(id: Long) {lock.lock()try {val stock = goods.getValue(id)goods.put(id, stock - 1)} catch (ex: Exception) {println(ex)} finally {lock.unlock()}
}

上面写法有以下问题:

  • 若有多个同步方法,将会竞争同一把锁
  • 加锁后可能忘记解锁
  • 重复的模板代码
fun <T> withLock(lock: Lock, action: () -> T) {lock.lock()try {action()} catch (ex: Exception) {println(ex)} finally {lock.unlock()}
}
fun buyGoods(id: Long) {val stock = goods.getValue(id)goods.put(id, stock - 1)
}
var lock: Lock = ReentrantLock()
withLock(lock, { buyGoods(1) })

上面使用高阶函数进行了优化,库函数也自带withLock()方法

fun buyGoods(id: Long) {val stock = goods.getValue(id)goods.put(id, stock - 1)
}
var lock: Lock = ReentrantLock()
lock.withLock({ buyGoods(1) })

相关文章:

  • Hadoop集群误删数据紧急恢复详细步骤
  • 从云原生视角看 AI 原生应用架构的实践
  • 爬虫cookie是什么意思
  • 助力游戏实现应用内运营闭环,融云游戏社交方案升级!
  • 【信息系统项目管理师知识点速记】组织通用管理:流程管理
  • kerberos HA高可用部署方案详解
  • 【鸿蒙学习笔记】页面和自定义组件生命周期
  • 使用Swoole开发高性能的Web爬虫
  • docker-compose搭建prometheus、grafana
  • React@16.x(43)路由v5.x(8)常见应用场景(5)- 滚动条复位
  • 0702_ARM6
  • 中国民间网络外交组织(CCND)
  • 【C++进阶学习】第五弹——二叉搜索树——二叉树进阶及set和map的铺垫
  • (PADS学习)第二章:原理图绘制 第一部分
  • [开源软件] 支持链接汇总
  • echarts的各种常用效果展示
  • ECMAScript入门(七)--Module语法
  • HTML-表单
  • STAR法则
  • vue2.0项目引入element-ui
  • 从重复到重用
  • 记录一下第一次使用npm
  • 设计模式(12)迭代器模式(讲解+应用)
  • 腾讯视频格式如何转换成mp4 将下载的qlv文件转换成mp4的方法
  • 网络应用优化——时延与带宽
  • 吴恩达Deep Learning课程练习题参考答案——R语言版
  • 项目管理碎碎念系列之一:干系人管理
  • 在GitHub多个账号上使用不同的SSH的配置方法
  • MiKTeX could not find the script engine ‘perl.exe‘ which is required to execute ‘latexmk‘.
  • CMake 入门1/5:基于阿里云 ECS搭建体验环境
  • ​ 轻量应用服务器:亚马逊云科技打造全球领先的云计算解决方案
  • #QT(TCP网络编程-服务端)
  • $分析了六十多年间100万字的政府工作报告,我看到了这样的变迁
  • (Matalb时序预测)WOA-BP鲸鱼算法优化BP神经网络的多维时序回归预测
  • (学习日记)2024.03.12:UCOSIII第十四节:时基列表
  • (一)SvelteKit教程:hello world
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • (转)我也是一只IT小小鸟
  • .bat批处理(八):各种形式的变量%0、%i、%%i、var、%var%、!var!的含义和区别
  • .Net CF下精确的计时器
  • .NET CORE 第一节 创建基本的 asp.net core
  • .NET CORE使用Redis分布式锁续命(续期)问题
  • .NET 表达式计算:Expression Evaluator
  • .NET(C#) Internals: as a developer, .net framework in my eyes
  • .Net多线程总结
  • .NET简谈互操作(五:基础知识之Dynamic平台调用)
  • .Net中wcf服务生成及调用
  • ::什么意思
  • ;号自动换行
  • @PreAuthorize与@Secured注解的区别是什么?
  • @RestControllerAdvice异常统一处理类失效原因
  • [ 攻防演练演示篇 ] 利用通达OA 文件上传漏洞上传webshell获取主机权限
  • [51nod1610]路径计数
  • [AI]文心一言爆火的同时,ChatGPT带来了这么多的开源项目你了解吗
  • [AutoSar]工程中的cpuload陷阱(三)测试