赞
踩
书接上回:Android Kotlin知识汇总(三)Kotlin 协程
在一个协程中,循环创建10个子协程且单独运行各自Default线程中,并让每个子协程对变量 i 进行1000次自增操作。示例如下:
- fun main() = runBlocking {
- var i = 0
- repeat(10) {
- val job = launch(Dispatchers.Default) {
- repeat(1000) {
- i++
- }
- }
- }
- println("i: $i")
- }
- /*
- 输出信息:i: 9310
- */
此时,这10个协程运行在不同的线程中,可能会出现并发问题,最终结果小于、等于10000。
我们知道,在 Java 中最简单的同步方式是 synchronized、Atomic、Lock等同步手段。事实上,在Kotlin 协程中也是可以同样适用这些同步手段的。
Kotlin特性之一:与 Java 的互操作性。由于 Kotlin 代码可编译为 JVM 字节码,意味着 Kotlin 利用现有的 Java 库直接调用。
Synchronized
使用 @Synchronized
注解修饰函数或 synchronized(){}
- fun main() = runBlocking {
- var i = 0
- @Synchronized
- fun add() {
- i++
- }
- repeat(10) {
- val job = launch(Dispatchers.Default) {
- repeat(1000) {
- add()
- }
- }
- }
- println("i: $i")
- }
- //输出信息:i: 10000

虽然 Kotlin 协程是基于 Java 线程的,但是它已经脱离了 Java 原本的范畴。
如果在 synchronized(){}
中调用suspend挂起函数,编译器会报错。
挂起函数会被翻译为 Continuation 的异步函数,造成 synchronized 代码块无法处理同步。
- suspend fun add() {
- i++
- }
因为是Java 的锁是阻塞式的,会影响协程的非阻塞式特性,所以在 Kotlin 协程中,不推荐使用 Java 中的同步锁。
Kotlin 官方提供了非阻塞式的锁:Mutex。
- public interface Mutex {
- public val isLocked: Boolean
-
- public suspend fun lock(owner: Any? = null)
-
- public fun unlock(owner: Any? = null)
- }
Mutex 是一个接口,lock() 方法是一个挂起函数,支持挂起和恢复,这是一个非阻塞式同步锁。
为了简化try、catch、lock、unlock的模板代码,Mutex提供了withLock{} 扩展函数。
- public suspend inline fun <T> Mutex.withLock(owner: Any? = null, action: () -> T): T {
- lock(owner)
- try {
- return action()
- } finally {
- unlock(owner)
- }
- }
使用示例如下:
- fun main() = runBlocking {
- val mutex = Mutex()
- var i = 0
- repeat(10) {
- val job = launch(Dispatchers.Default) {
- repeat(1000) {
- //模板代码
- try {
- mutex.lock()
- i++
- } catch (e: Exception) {
- println(e)
- } finally {
- mutex.unlock()
- }
- //简化代码
- mutex.withLock {
- i++
- }
- }
- }
- }
- println("i: $i")
- }
- //输出信息:i: 10000
-

另外还有Actor 并发同步方式,本质是 Channel管道消息的简单封装。在 actor{} 外部,发送了10000次 AddMsg 消息,最后发送一次 ResultMsg,获取计算结果。
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。