Part 1 · 1 chapters · ~8 min
Locks and Condition Variables
Mutexes protecting invariants, lock granularity, reader-writer locks, condition variables and the wait loop, semaphores for bounded resources, monitors and synchronized blocks, and the same primitives in Go, Java, Rust, Python and Node.
3
Primitives across languages
| primitive | Go | Java | Rust | Python |
|---|---|---|---|---|
| mutex | sync.Mutex | synchronized, ReentrantLock | Mutex<T> (data inside the lock) | threading.Lock |
| reader-writer | sync.RWMutex | ReentrantReadWriteLock | RwLock<T> | (third-party) |
| condition | sync.Cond (channels usually instead) | wait/notify, Condition | Condvar | threading.Condition |
| semaphore | buffered channel | Semaphore | tokio::sync::Semaphore | threading.Semaphore, asyncio.Semaphore |
code
// Rust puts the data inside the lock: you cannot touch it without holding the guard
use std::sync::{Arc, Mutex};
let balance = Arc::new(Mutex::new(100_i64));
{ let mut b = balance.lock().unwrap(); if *b >= 80 { *b -= 80; } } // guard dropped here: unlocked
// Go: a semaphore as a buffered channel limits concurrency to 10
sem := make(chan struct{}, 10)
for _, u := range urls { sem <- struct{}{}; go func(u string) { defer func() { <-sem }(); fetch(u) }(u) }A lock protects an invariant ("balance is never negative and equals the sum of postings"), not a variable. Hold it across every step that must see the invariant intact, and for no longer: never across network calls or awaits on slow work.