importkotlinx.coroutines.sync.Muteximportkotlinx.coroutines.sync.withLockvalmutex=Mutex()suspendfunprotectedOperation(){mutex.withLock{// Critical section - only one coroutine at a time// Modify shared state safely here}}
// ✅ Good: Lock only for critical sectionsuspendfunupdateUser(userId:String,name:String){valvalidated=validateName(name)// Outside lockmutex.withLock{userCache[userId]=validated// Only this needs protection}notifyObservers(userId)// Outside lock}// ❌ Bad: Holding lock during slow operationssuspendfunupdateUserSlow(userId:String,name:String){mutex.withLock{valvalidated=validateName(name)// Slow operation inside lockuserCache[userId]=validatednotifyObservers(userId)// I/O inside lock}}
3. 避免嵌套锁
互斥锁不可重入。避免两次获取同一个锁:
1234567891011121314151617181920212223
// ❌ Bad: Deadlock!suspendfunproblematic(){mutex.withLock{helperFunction()// Tries to acquire mutex again}}suspendfunhelperFunction(){mutex.withLock{// Will suspend forever}}// ✅ Good: Restructure to avoid nestingsuspendfunbetter(){mutex.withLock{helperFunctionUnsafe()// No lock acquisition}}funhelperFunctionUnsafe(){// Assumes caller holds lock}
4. 优先考虑无锁替代方案
对于简单操作,原子类型速度更快:
1234567891011121314151617
// ✅ Better for simple countersclassAtomicCounter{privatevalcounter=AtomicInteger(0)funincrement()=counter.incrementAndGet()funget()=counter.get()}// ❌ Overkill for a simple counterclassMutexCounter{privatevarcounter=0privatevalmutex=Mutex()suspendfunincrement(){mutex.withLock{counter++}}}
5.文档锁不变量
明确锁保护的对象:
123456789101112
classUserCache{privatevalmutex=Mutex()// Protects userMap and lastUpdateprivatevaluserMap=mutableMapOf<String,User>()privatevarlastUpdate=0LsuspendfunupdateUser(id:String,user:User){mutex.withLock{userMap[id]=userlastUpdate=System.currentTimeMillis()}}}
互斥锁 vs. 其他同步方法
互斥锁 vs. synchronized
123456789101112131415161718192021
// Traditional synchronized (blocks thread)classSynchronizedCounter{privatevarcount=0@Synchronizedfunincrement(){count++// Thread blocked while waiting}}// Mutex (suspends coroutine)classMutexCounter{privatevarcount=0privatevalmutex=Mutex()suspendfunincrement(){mutex.withLock{count++// Coroutine suspended, thread free}}}
何时该用哪个:
对于非暂停代码和旧版 Java 互操作,请使用 synchronized
对于暂停函数和基于协程的代码,请使用 Mutex
在协程上下文中,Mutex 效率更高,因为线程不会被阻塞
互斥锁 vs. 信号量
12345678910111213141516
// Mutex: Only one coroutine at a timevalmutex=Mutex()// Semaphore: N coroutines at a timevalsemaphore=Semaphore(permits=3)// Example: Rate limiting API callsclassApiClient{privatevalsemaphore=Semaphore(5)// Max 5 concurrent requestssuspendfunmakeRequest(endpoint:String):Response{semaphore.withPermit{returnhttpClient.get(endpoint)}}}
// Mutex: Imperative state managementclassMutexState{privatevarstate=0privatevalmutex=Mutex()suspendfunupdateState(transform:(Int)->Int){mutex.withLock{state=transform(state)}}}// StateFlow: Reactive state managementclassFlowState{privateval_state=MutableStateFlow(0)valstate:StateFlow<Int>=_state.asStateFlow()funupdateState(transform:(Int)->Int){_state.update(transform)// Thread-safe built-in}}
何时使用哪个:
需要自定义同步逻辑时使用 Mutex
使用 StateFlow 进行内置线程安全的可观察状态
StateFlow 更适合 UI 状态和响应式架构
Mutex 与原子类型
123456789101112131415161718192021
// AtomicInteger: Lock-free for simple operationsclassAtomicCounter{privatevalcounter=AtomicInteger(0)funincrement()=counter.incrementAndGet()funaddAndGet(delta:Int)=counter.addAndGet(delta)}// Mutex: For complex operationsclassComplexCounter{privatevarcounter=0privatevarhistory=mutableListOf<Int>()privatevalmutex=Mutex()suspendfunincrement(){mutex.withLock{counter++history.add(counter)// Multiple operations}}}
何时使用哪个:
使用原子类型进行单变量操作(计数器、标志)
需要协调多个变量时使用 Mutex
原子操作速度更快,但受限于特定操作
常见陷阱
1. 忘记使用 suspend
互斥操作需要暂停:
123456789
// ❌ Won't compilefunbroken(){mutex.withLock{}// Error: suspend function called in non-suspend context}// ✅ Correctsuspendfuncorrect(){mutex.withLock{}}
classUserRepository(privatevalapi:UserApi,privatevaldatabase:UserDatabase){privatevalcache=mutableMapOf<String,User>()privatevalmutex=Mutex()suspendfungetUser(userId:String):User?{// Check cache first (read lock)mutex.withLock{cache[userId]?.let{returnit}}// Try database (outside lock)database.getUser(userId)?.let{user->mutex.withLock{cache[userId]=user}returnuser}// Fetch from API (outside lock)returntry{valuser=api.fetchUser(userId)mutex.withLock{cache[userId]=userdatabase.insertUser(user)}user}catch(e:Exception){null}}suspendfunupdateUser(user:User){mutex.withLock{cache[user.id]=userdatabase.updateUser(user)}}suspendfunclearCache(){mutex.withLock{cache.clear()}}}