MST

星途 面试题库

面试题:Kotlin并发编程中的线程安全问题及解决

在Kotlin的并发编程场景下,当多个协程同时访问和修改共享资源时,会面临哪些线程安全问题?请举例说明,并阐述如何使用`@Synchronized`注解、`Mutex`等方式来确保线程安全。
47.6万 热度难度
编程语言Kotlin

知识考点

AI 面试

面试题答案

一键面试

线程安全问题

  1. 竞态条件(Race Condition):多个协程同时访问和修改共享资源,最终结果取决于协程执行的顺序。例如,假设有一个共享变量count,多个协程对其进行自增操作:
var count = 0
fun main() = runBlocking {
    val jobs = List(100) {
        launch {
            repeat(100) {
                count++
            }
        }
    }
    jobs.forEach { it.join() }
    println("Final count: $count")
}

由于多个协程同时访问和修改count,最终结果可能小于预期的10000,因为不同协程的自增操作可能相互覆盖。

  1. 数据不一致(Data Inconsistency):共享资源的状态可能处于不一致的中间状态。比如,一个协程在更新对象的多个相关字段时,另一个协程在更新过程中读取该对象,可能获取到不完整或不一致的数据。

使用@Synchronized注解确保线程安全

在Kotlin中,@Synchronized注解可以应用于方法,确保同一时间只有一个线程(或协程)能够执行该方法,从而保护共享资源。例如:

class Counter {
    private var count = 0
    @Synchronized
    fun increment() {
        count++
    }
    @Synchronized
    fun getCount(): Int {
        return count
    }
}
fun main() = runBlocking {
    val counter = Counter()
    val jobs = List(100) {
        launch {
            repeat(100) {
                counter.increment()
            }
        }
    }
    jobs.forEach { it.join() }
    println("Final count: ${counter.getCount()}")
}

这里,@Synchronized确保了incrementgetCount方法在同一时间只有一个协程可以执行,避免了竞态条件。

使用Mutex确保线程安全

Mutex(互斥锁)是一种同步原语,用于控制对共享资源的访问。只有获取到锁的协程才能访问共享资源。例如:

import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
val mutex = Mutex()
var count = 0
fun main() = runBlocking {
    val jobs = List(100) {
        launch {
            repeat(100) {
                mutex.lock()
                try {
                    count++
                } finally {
                    mutex.unlock()
                }
            }
        }
    }
    jobs.forEach { it.join() }
    println("Final count: $count")
}

在这段代码中,mutex.lock()获取锁,确保只有一个协程可以进入临界区(修改count的代码块),mutex.unlock()释放锁,允许其他协程获取锁并访问共享资源,从而保证了线程安全。