Kotlin 中的并发与多线程:高级水平
\n在现代 Kotlin 开发中,尤其是对于服务器端和 Android 应用程序,良好的并发管理是性能和响应能力的关键。在高级水平上,仅仅启动一个协程是不够的。需要理解如何有效地同步数据访问、管理线程以及避免“地狱般的”锁。在本文中,我们将深入探讨高级技术:从 kotlinx.coroutines 的细微之处到线程安全集合和通道。
1. 深入理解协程:结构化并发与作用域
\n高级工作的基础是 结构化并发。这是一个原则,即协程的生命周期绑定到其作用域。如果父协程被取消,其所有子任务将自动终止。这可以防止内存泄漏和不受控制的进程。
\n在高级水平上,您应该创建自己的作用域,而不是依赖全局的 GlobalScope。
import kotlinx.coroutines.*\nimport kotlin.coroutines.CoroutineContext\n\nclass DataRepository {\n // 自定义作用域,包含调度器和异常处理器\n private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob() + CoroutineExceptionHandler { _, throwable ->\n println("未处理的错误:${throwable.message}")\n })\n\n fun loadData() {\n scope.launch {\n // 子协程\n val data = async { fetchFromNetwork() }\n val cache = async { loadFromCache() }\n process(data.await(), cache.await())\n }\n }\n\n fun cleanup() {\n scope.cancel() // 取消作用域中的所有协程\n }\n}\n\n当一个子协程的失败不应取消其他协程时,请使用 SupervisorJob。这对于 UI 层或并行的独立请求至关重要。
2. 线程安全集合与原子操作
\n即使使用协程,如果您处理共享的可变数据,也需要同步。Kotlin 提供了几种方法:
\n- \n
- 原子类型(
AtomicInteger、AtomicReference)——用于简单的计数器和标志。 \n - 线程安全集合(
ConcurrentHashMap、CopyOnWriteArrayList)——用于复杂的数据结构。 \n - Mutex 来自
kotlinx.coroutines——用于协程内部的临界区。 \n
import kotlinx.coroutines.*\nimport kotlinx.coroutines.sync.Mutex\nimport kotlinx.coroutines.sync.withLock\nimport java.util.concurrent.ConcurrentHashMap\nimport java.util.concurrent.atomic.AtomicInteger\n\nclass SafeCounter {\n private val mutex = Mutex()\n private var counter = 0\n\n suspend fun increment() {\n mutex.withLock {\n counter++ // 临界区\n }\n }\n\n fun getCounter(): Int = counter\n}\n\nclass CacheManager {\n private val cache = ConcurrentHashMap<String, String>()\n private val hitCount = AtomicInteger(0)\n\n fun put(key: String, value: String) {\n cache[key] = value\n }\n\n fun get(key: String): String? {\n val result = cache[key]\n if (result != null) hitCount.incrementAndGet()\n return result\n }\n}\n\n重要:Mutex 是一个挂起函数,因此它不会阻塞线程,而是挂起协程。这比 synchronized 更高效。
3. 通道 (Channels) 和 Flow:响应式数据流
\n为了在协程之间传输数据,请使用 Channels(协程版的 BlockingQueue)和 Flow(冷异步流)。
通道:生产者-消费者
\nimport kotlinx.coroutines.channels.*\nimport kotlinx.coroutines.*\n\nfun Corout