`Mutex` allows one goroutine at a time — for both reads and writes. `RWMutex` allows multiple concurrent readers OR one writer — much better when reads dominate.
`select` is like a switch for channels — runs whichever case is ready. Use `default` for non-blocking sends/receives; `case <-time.After(d)` for timeouts.
Channels are typed pipes between goroutines. Unbuffered = synchronous handoff; buffered = up to N values queued. Close a channel to signal "no more values" — receivers see ok=false.
Distribute work across N workers (fan-out), then merge their results back into one channel (fan-in). Used when you can't process items strictly in order but want to retain output as one stream.
For shared counters and flags, `AtomicU64` / `AtomicBool` etc. are much faster than `Mutex`. Operations like `fetch_add` are single CPU instructions on most architectures.
Limit how many threads can enter a critical section. `acquire()` blocks until a permit is available; `release()` returns one. Use for rate limits, connection pools, or any "max N at a time" pattern.
`golang.org/x/sync/errgroup` runs N goroutines, returns the first error, and cancels the others via a shared context. The right pattern for parallel I/O where any failure should abort the rest.
`context.Context` propagates deadlines, cancellation, and request-scoped values down a call chain. EVERY blocking / long-running function should take a `ctx context.Context` as its first parameter.
A pipeline is a chain of stages connected by channels — each stage runs in its own goroutine. Classic Go pattern for streaming transformations with backpressure built in.
A goroutine that's blocked forever on a channel send/receive leaks — it's never garbage-collected. Always pair channels with `select { case <-ctx.Done(): return }` to give them an exit path.
`sync.Pool` keeps a pool of reusable objects to reduce allocator pressure in hot paths. Good for byte buffers, JSON encoders, or anything you allocate frequently and only need briefly.
Run hundreds of coroutines but cap how many are in-flight at any moment. asyncio.Semaphore inside the task body is the cleanest way to "do at most 10 of these at a time."
`CompletableFuture` is the idiomatic way to compose async work. `thenApply` for sync transforms, `thenCompose` for async chains (flatMap), `exceptionally` for fallback on failure.
Java 21's virtual threads are millions-of-them cheap — JVM multiplexes them onto a small carrier pool. Replaces async/reactive code for most I/O-bound workloads: just write blocking code that doesn't actually block a kernel thread.
Block one or more threads until a count of events occurs. Set the count up front; each event calls `countDown()`; waiters call `await()`. Classic "wait until all workers are ready" pattern.