面试题答案
一键面试线程安全问题
- 竞态条件(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
,因为不同协程的自增操作可能相互覆盖。
- 数据不一致(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
确保了increment
和getCount
方法在同一时间只有一个协程可以执行,避免了竞态条件。
使用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()
释放锁,允许其他协程获取锁并访问共享资源,从而保证了线程安全。