Lock Contention Profiling
Lock contention profiling finds the locks where threads wait, so the optimization targets the lock that bounds throughput rather than the lock that is held but never contended.
Definition
Lock contention profiling is the measurement of the time threads spend waiting to acquire locks, identifying the specific locks and call sites where contention bounds throughput, so that the optimization — sharding, lock-free, narrower critical section — targets the contended lock rather than the held-but-uncontended one.
Context and scope
Applied in multithreaded performance tuning, using profiler contention views (perf, JFR, pprof) to find the bottleneck lock.
Common misconceptions
- A lock that is held a long time is the bottleneck — it is the bottleneck only if other threads want it; a long-held uncontended lock costs nothing
- Reducing critical section time always helps — it helps the contended lock; for an uncontended lock it adds complexity for no gain
Anti-patterns
- Optimizing a lock that the profiler shows is held often but never waited on, paying complexity for no throughput gain
- Reducing the critical section by moving work out, but moving it to a second contended lock and just moving the bottleneck
Related concepts
Authoritative source
What it is
Lock contention profiling is the measurement of the time threads spend waiting to acquire locks, identifying the specific locks and call sites where contention bounds throughput, so that the optimization — sharding, lock-free, narrower critical section — targets the contended lock rather than the held-but-uncontended one. Applied in multithreaded performance tuning, using profiler contention views (perf, JFR, pprof) to find the bottleneck lock. Performance is a distribution, not a number: the tail determines user experience, and the mean hides the outliers that cause abandonment.
How it works
Measurement targets percentiles at the workload’s actual concurrency, not a single sequential run. The fast path is kept fast by deferring work that is not on it — lazy initialization, coalescing writes, avoiding allocation in hot loops. Profiling finds the bottleneck; micro-optimization without a profile optimizes the wrong thing. Constant factors matter, but algorithmic complexity dominates as scale grows.
When to optimize and pitfalls
Optimize when a measurement shows a concrete cost — latency budget burn, compute spend, user-visible jank. The pitfall is optimizing for the benchmark rather than the workload: a synthetic test that does not reproduce the production access pattern produces a local maximum that hurts globally. Another is trading memory for speed without accounting for the GC or eviction cost the extra allocation introduces.