Golang / GoLang Concurrency Mastery Interview Questions
When do you use sync.Mutex versus sync.RWMutex, and what are the critical usage rules?
sync.Mutex provides mutual exclusion — at most one goroutine holds the lock at any time. sync.RWMutex distinguishes readers from writers, allowing multiple concurrent readers OR one exclusive writer — more efficient for read-heavy workloads.
// sync.Mutex â mixed or write-heavy access type BankAccount struct { mu sync.Mutex balance float64 } func (a *BankAccount) Deposit(amount float64) { a.mu.Lock() defer a.mu.Unlock() // ALWAYS defer â fires even on panic or early return a.balance += amount } func (a *BankAccount) Balance() float64 { a.mu.Lock() defer a.mu.Unlock() return a.balance } // sync.RWMutex â read-heavy (reads >> writes) type SafeConfig struct { mu sync.RWMutex data map[string]string } func (c *SafeConfig) Get(key string) string { c.mu.RLock() // multiple goroutines can RLock at the same time defer c.mu.RUnlock() return c.data[key] } func (c *SafeConfig) Set(key, val string) { c.mu.Lock() // exclusive: no readers OR writers allowed defer c.mu.Unlock() c.data[key] = val } // CRITICAL MISTAKES: // 1. NEVER copy a Mutex after first use // Copying duplicates internal state â broken synchronisation // Always use *BankAccount, never BankAccount by value // 2. Mutex is NOT reentrant // A goroutine that calls Lock() while already holding it â DEADLOCK // 3. Writer starvation protection in RWMutex: // When a writer is waiting, new readers are blocked // even if existing readers still hold RLock
| Condition | Prefer |
|---|---|
| Write-heavy or mixed reads/writes | sync.Mutex |
| Read-dominant (e.g. config, cache, registry) | sync.RWMutex |
| Very short critical section (<1 µs) | sync.Mutex (RWMutex overhead can dominate) |
| Single integer counter | sync/atomic (no lock at all) |
More Related questions...