Kotlin基础——异步和并发

异步

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

  • 线程切换频繁时会导致大量的开销
  • 回调会使代码更加复杂,且会存在多层次的回调

使用协程则可以避免上述问题

协程Coroutine

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

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

使用Coroutine需要导入包,如下通过launch构造了一个协程

GlobalScope.launch {
    delay(1000L)
    println("World")
}
println("Hello, ")
Thread.sleep(2000)
  • 主线程输出Hello,协程输出World
  • delay()挂起协程,但不会阻塞线程,sleep()会阻塞线程
  • 协程的切换是在线程之上,可以由程序自己来控制,避免了线程切换的开销

launch和runBlocking

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 startTime = System.currentTimeMillis()
    val one = searchOne()
    val two = searchTwo()
    println("The items is ${one} and ${two}")
    println("Cost time is ${System.currentTimeMillis() - startTime} ms")
}

suspend fun searchOne(): String {
    delay(1000L)
    return "item-one"
}

suspend fun searchTwo(): String {
    delay(1000L)
    return "item-two"
}

打印如下

The items is item-one and item-two
Cost time is 2010 ms

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

  • 使用async相当于创建了一个子协程,会和其他子协程一样并行工作
  • async返回Deferred,其是一个非阻塞可取消且带有结果的job,而launch也返回job但无结果
  • 利用await可以从Deferred获取结果
fun test2() = runBlocking<Unit> {
	val startTime = System.currentTimeMillis()
    val one = async { searchOne() }
    val two = async { searchTwo() }
    println("search is ${one.await()} and ${two.await()}")
    println("Cost time is ${System.currentTimeMillis() - startTime} ms")
}

打印如下

search is item-one and item-two
Cost time is 1006 ms

共享资源控制

Synchronized

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

class Shop {
    val goods = hashMapOf<Long, Int>()

    init {
        goods.put(1, 10)
        goods.put(2, 15)
    }

    @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) })
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值