skip to content

What modes does StampedLock support and how does mode conversion (e.g. tryConvertToWriteLock) work?

level: principalimportance: nice to knowfreq 24%

answer

  1. Three modes: write (exclusive), read (shared), optimistic (no lock)
  2. tryConvertTo{Write,Read,Optimistic}Read
  3. Returns new stamp on success, 0 on failure — always check
  4. Upgrade idiom: convert, else unlock+writeLock+re-test
  5. Conversions don't add reentrancy; no Conditions

basics

~20 s

StampedLock has three modes: writing (exclusive), reading (shared), and optimistic reading (no lock). Conversion methods like tryConvertToWriteLock take your current stamp and try to switch modes; they return a new stamp on success or 0 on failure, so you must check the result.

solid answer

~40 s

StampedLock offers three access modes: an exclusive write lock (writeLock), a shared read lock (readLock), and a lock-free optimistic read (tryOptimisticRead). On top of these it provides mode-conversion methods — tryConvertToWriteLock, tryConvertToReadLock, and tryConvertToOptimisticRead — each taking the current stamp and returning a new stamp on success or 0 on failure. The common idiom is starting optimistic or read-locked, discovering you need to write, and attempting tryConvertToWriteLock(stamp): if it returns non-zero you proceed under the write lock with the new stamp; if it returns 0 you fall back to releasing and acquiring writeLock() outright. This lets you upgrade safely without the unconditional deadlock that read-to-write upgrade causes in ReentrantReadWriteLock. You always release with the stamp the lock currently holds (unlockWrite/unlockRead, or the generic unlock). Conversions are 'try' operations — never assume success.

go deeper

for a junior

Recognizes that StampedLock has read, write, and optimistic modes.

for a middle

Can name the three modes and knows conversion methods exist that return a stamp or 0.

for a senior

Writes the convert-or-fall-back-to-writeLock upgrade idiom correctly, checks the 0 return, and re-tests the condition after re-acquiring.

for a principal

Judges when mode conversion is worth the complexity versus a simpler lock or lock-free approach, ensures stamp-handling correctness under review, and accounts for non-reentrancy and absent Conditions in the design.

### The three modes `StampedLock` exposes three distinct ways to access guarded state, each returning a `long` **stamp** (a version/ownership token): 1. **Write mode** — `writeLock()` returns a stamp for **exclusive** access. No other reader or writer proceeds while it is held. Release with `unlockWrite(stamp)`. 2. **Read mode** — `readLock()` returns a stamp for **shared** access. Many readers coexist; writers wait. Release with `unlockRead(stamp)`. 3. **Optimistic read** — `tryOptimisticRead()` returns a stamp **without taking any lock**; you read into locals and call `validate(stamp)` to confirm no writer intervened (returns 0 if a write lock is currently held). There are also blocking-with-timeout and interruptible variants (`tryWriteLock`, `tryReadLock`, `writeLockInterruptibly`, etc.). ### Why mode conversion exists A frequent pattern is: *read some state, decide based on it whether a write is needed, and if so, write.* With `ReentrantReadWriteLock` you cannot **upgrade** from the read lock to the write lock — it deadlocks unconditionally — so you must release the read lock and re-acquire as a writer, opening a window where another thread can change the state. `StampedLock` provides **conditional** conversion methods that attempt the transition atomically when possible. ### The conversion methods Each takes the **current stamp** and returns a **new stamp** on success or **0** on failure: - `tryConvertToWriteLock(long stamp)` — from optimistic/read to write. Succeeds immediately if already write-locked; if read-locked and no other reader, it can convert; from a *validated optimistic* stamp it can acquire the write lock if immediately available. Returns 0 if it cannot. - `tryConvertToReadLock(long stamp)` — from optimistic/write to read (a **downgrade** when coming from write). - `tryConvertToOptimisticRead(long stamp)` — release to a lock-free optimistic stamp if the version matches. ### The canonical upgrade idiom ```java void moveIfAtOrigin(double newX, double newY) { long stamp = sl.readLock(); try { while (x == 0.0 && y == 0.0) { long ws = sl.tryConvertToWriteLock(stamp); // attempt read -> write if (ws != 0L) { // success: we now hold the write lock stamp = ws; // adopt the new stamp x = newX; y = newY; break; } else { // failed: release read, take write outright sl.unlockRead(stamp); stamp = sl.writeLock(); // loop re-checks the condition under the write lock } } } finally { sl.unlock(stamp); // generic unlock with whatever stamp we hold } } ``` Key points: - The return value is **always checked**: non-zero means proceed with the *new* stamp; zero means fall back. - On fallback you **release then re-acquire**, and you **re-test the condition** because state may have changed in the gap. - `unlock(stamp)` is a generic release that works for whichever mode the stamp represents. ### Downgrading Going write→read via `tryConvertToReadLock` lets a writer narrow to shared access while staying continuously protected — analogous to `ReentrantReadWriteLock`'s downgrade but expressed through stamps. ### Discipline and pitfalls - **Always use the latest stamp.** Each successful operation hands back a new stamp; the old one is stale and must not be used to unlock. - **'try' means it can fail.** Treat 0 as a normal outcome with a defined fallback, never an error to ignore. - **Still non-reentrant.** Conversions don't make the lock reentrant; a separate re-acquire on the same thread still self-deadlocks. - **No Conditions.** For wait/signal coordination you need a different primitive. - Mode conversion is an **advanced/expert** tool; for most code a straightforward writeLock or ReentrantReadWriteLock is clearer and less error-prone. Reach for conversions only when the read-then-maybe-write pattern is hot enough to matter and you can prove the stamp handling correct. ### When this is worth it Principal-level judgment: mode conversion shines in hot, read-mostly structures where you occasionally need to promote to a write without dropping protection — concurrent caches, spatial structures, or counters with conditional updates. Measure first; the readability cost is real, and a simpler lock or a lock-free `Atomic*`/`VarHandle` approach may serve better.

  • Why is StampedLock's tryConvertToWriteLock safer than read-to-write upgrade in ReentrantReadWriteLock?
    ReentrantReadWriteLock's read-to-write upgrade deadlocks unconditionally, so you must release the read lock and re-acquire, leaving a gap where state can change. tryConvertToWriteLock attempts the upgrade atomically when possible and returns 0 (a checkable failure) otherwise, letting you choose a controlled fallback that re-validates state.
  • After a successful conversion, which stamp do you use to unlock?
    The new stamp returned by the conversion method. Each successful StampedLock operation yields a fresh stamp; the previous one is stale. Using the generic unlock(stamp) with the latest stamp releases whichever mode you currently hold.

saying these in an interview costs you the question

  • Ignoring the 0 return value and assuming conversion always succeeds
  • Unlocking with a stale stamp after a successful conversion returned a new one
  • Forgetting to re-check the condition after the release-and-reacquire fallback
  • Thinking mode conversion makes StampedLock reentrant or gives it Conditions

context