What is a Mutex in Go and how does it differ from a channel for synchronization?
Learn what a Mutex is in Go, how sync.Mutex differs from channels for synchronization, when to use each, code examples and common interview mistakes.
Expected Interview Answer
A Mutex (sync.Mutex) is a mutual-exclusion lock that lets only one goroutine access shared state at a time; a channel synchronizes goroutines by passing data (and ownership) between them instead of guarding a shared variable.
You call mu.Lock() before touching shared memory and mu.Unlock() after, so concurrent goroutines serialize their access and avoid data races. A channel takes a different philosophy — 'do not communicate by sharing memory; share memory by communicating' — moving a value from one goroutine to another so only one owns it at a time. Mutexes are best for protecting a small piece of state with short critical sections; channels are best for handing off work, signaling events, or coordinating pipelines.
- Mutex gives simple, low-overhead protection for shared state
- Channels express ownership transfer and communication clearly
- Both prevent data races detectable by the -race detector
- sync.RWMutex allows many concurrent readers, one writer
- Choosing the right tool keeps concurrent code readable and correct
AI Mentor Explanation
A Mutex is like the single pair of pads in the dressing room: only one batter can wear them and go out to the crease at a time, and the next player must wait until the pads come back before padding up. A channel is different — it is the running between wickets, where the strike is physically handed from one batter to the other so only the one on strike faces the ball, ownership passing cleanly with each completed run.
Step-by-Step Explanation
Step 1
Spot the shared state
Identify a variable or struct accessed by multiple goroutines that could race.
Step 2
Choose the tool
Use a Mutex to guard in-place shared state; use a channel to hand data or signals between goroutines.
Step 3
Lock and defer unlock
Call mu.Lock(), then defer mu.Unlock() so the critical section is always released, even on panic.
Step 4
Keep critical sections small
Do minimal work while holding the lock to reduce contention and avoid deadlocks.
Step 5
Verify with the race detector
Run go test -race or go run -race to confirm no data races remain.
What Interviewer Expects
- Knowing sync.Mutex serializes access to shared memory
- Understanding 'share memory by communicating' channel philosophy
- When to pick a Mutex vs a channel
- Awareness of RWMutex for read-heavy workloads
- Using defer Unlock and the -race detector
Common Mistakes
- Copying a sync.Mutex by value, which breaks the lock
- Forgetting to Unlock, causing deadlock
- Using channels where a simple Mutex is clearer and faster
- Holding the lock while doing slow I/O
- Assuming a Mutex makes the whole program thread-safe automatically
Best Answer (HR Friendly)
“A Mutex is like a lock on a shared item so only one worker uses it at a time, while a channel is like passing an item between workers so only whoever holds it can use it. In Go you reach for a Mutex to protect shared data and a channel to hand work or messages between goroutines.”
Code Example
type Counter struct {
mu sync.Mutex
n int
}
func (c *Counter) Inc() {
c.mu.Lock()
defer c.mu.Unlock()
c.n++
}jobs := make(chan int, 3)
go func() {
for j := range jobs {
fmt.Println("processing", j)
}
}()
jobs <- 1
jobs <- 2
close(jobs)Follow-up Questions
- When would you choose sync.RWMutex over sync.Mutex?
- What is a deadlock and how can a Mutex cause one?
- How does Go's race detector find data races?
- What does 'share memory by communicating' mean in practice?
- How do sync.Once and sync.WaitGroup complement a Mutex?
MCQ Practice
1. What is the primary purpose of sync.Mutex in Go?
A Mutex ensures only one goroutine enters a critical section at a time, serializing access to shared state to prevent data races.
2. Which Go proverb best describes channel-based synchronization?
Channels favor transferring data ownership between goroutines rather than guarding shared memory with locks.
3. Why should you avoid copying a sync.Mutex by value?
A copied Mutex no longer shares lock state with the original, so goroutines can enter the critical section simultaneously.
Flash Cards
What does sync.Mutex do? — Provides mutual exclusion so only one goroutine accesses shared state at a time via Lock/Unlock.
Mutex vs channel? — Mutex guards shared memory in place; a channel transfers data/ownership between goroutines.
Why defer Unlock? — It guarantees the lock is released even if the function returns early or panics.
What is sync.RWMutex? — A lock allowing many concurrent readers but only one writer, ideal for read-heavy state.
Continue Learning
Related Interview Questions
What is the Go memory model and what does the happens-before relationship mean?
hard
How do you detect and avoid race conditions in Go?
medium
What are channels in Go and how do they enable communication between goroutines?
medium
What is the difference between buffered and unbuffered channels in Go?
medium