Does lock guarantee acquired in order requested?
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
A lock guarantees mutual exclusion, not fairness. It ensures that only one thread enters the protected critical section at a time, but it does not usually guarantee that waiting threads acquire the lock in the same order they requested it. Whether request order is respected depends on the specific lock implementation.
That difference matters because many developers assume "thread-safe" also means "first come, first served." Those are separate properties. A program can be perfectly correct under an unfair lock, and it can also have user-visible latency problems because acquisition order is not predictable.
What a Plain Lock Actually Guarantees
A basic lock normally guarantees:
- only one thread owns the lock at a time
- other threads block, spin, or wait until it becomes available
- the protected region is serialized
What it usually does not promise is FIFO ordering among waiters. If thread A starts waiting before thread B, thread B may still acquire the lock first after release.
That can happen for several reasons:
- the runtime wakes waiters in a non-FIFO way
- the operating system scheduler favors a different thread
- the lock intentionally allows unfair acquisition for throughput reasons
So the right default assumption is "no ordering guarantee unless the API documents one."
Fairness Depends on the Lock Type
Some runtimes expose both fair and unfair lock options. Java is a good example:
The default constructor creates an unfair lock. Passing true asks for a fairness policy that is closer to acquisition in waiting order.
Even then, fair does not mean perfectly deterministic under every scheduling condition. It means the implementation makes a stronger effort to respect queue order among contenders.
Many mainstream lock types do not provide fairness guarantees at all because unfair locks often perform better under contention.
Why Unfair Locks Often Perform Better
Fairness sounds obviously good until you account for cost. A lock that always wakes the oldest waiter may trigger more context switching and may miss opportunities to let a currently running thread reacquire the lock cheaply.
That is why some runtimes choose unfair behavior by default. They optimize for throughput and average latency rather than strict queue discipline.
For many applications, that is the right tradeoff. If the only requirement is correctness, a fair lock may add overhead without solving a real problem.
Use a Queue When Order Truly Matters
If the application depends on request order, a plain lock is often the wrong abstraction even if a fair mode exists. Order-sensitive work is usually clearer when modeled explicitly through a queue, a worker thread, or a message-passing pipeline.
For example, instead of many threads racing for a lock to process jobs, a queue-based design makes the intended ordering obvious:
This does not just serialize access. It models ordered processing directly, which is often a better fit than hoping a lock behaves fairly enough.
Common Pitfalls
The biggest mistake is assuming a lock guarantees first-come, first-served acquisition just because multiple threads are waiting.
Another common problem is inferring fairness from light testing. A lock may appear orderly under low contention and behave very differently under real load.
It is also easy to reach for a fair lock when the program really wants an explicit queue or scheduler. Fairness and ordering are related, but they are not interchangeable design concepts.
Finally, lack of fairness can increase starvation risk. A thread may wait much longer than others even though the code remains logically correct.
Summary
- A normal lock guarantees mutual exclusion, not acquisition order.
- Fairness exists only when the specific lock implementation documents it.
- Unfair locks are common because they often deliver better throughput.
- If strict processing order matters, model that requirement explicitly with queues or schedulers.
- Do not assume a lock is FIFO unless the API says it is.
Related reading
- Does MinGW-w64 support stdthread out of the box when using the Win32 threading model?
- Does multicore computing using R's doParallel package use more memory?
- Does Netty violate the contract of Future.cancel... method?
- Does node.js preserve asynchronous execution order?
- Does Parallel.ForEach limit the number of active threads?
- Does Parallel.ForEach limit the number of active threads?
- Does PHP have threading?
- Does python-requests support HTTP2 and asynchronous calls?
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.