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 { 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 { 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() 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 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) })
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!
