What is the difference between optimistic and pessimistic locking, and where does each apply?
Pessimistic locking assumes a conflict is likely and acquires a lock before touching the shared resource at all, as with synchronized, ReentrantLock, or a database row-level lock obtained through SELECT FOR UPDATE. It is always correct, but its throughput degrades under contention since threads have to queue up and wait their turn; it's the right choice for write-heavy workloads, situations where high contention is expected, or when the critical section is relatively long. Optimistic locking instead assumes conflicts are rare, proceeds without taking any lock up front, and only verifies at the point of commit that nothing else interfered, as with an AtomicInteger CAS loop, StampedLock's optimistic-read mode, or a database version column pattern where an update statement includes WHERE version = N and the caller checks that exactly one row was affected. It's fast when contention really is low, but performance can degrade if conflicts turn out to be common and the operation has to retry repeatedly; it fits read-heavy workloads with rare conflicts and short check-and-update operations well. In Java terms, a CAS loop built on AtomicReference is a form of optimistic locking, while the synchronized keyword is inherently pessimistic.
Ready to master this question?
Generate a complete walkthrough — background, the full answer in plain language, a working code example explained line by line, a real-world scenario, common mistakes, and how this same question gets asked in different ways.
Sign in to generate a response