quarkusio/quarkus · error · jakarta.enterprise.context.control.LockException

Write lock not acquired in ${time} ms

Error message

Write lock not acquired in ${time} ms

What it means

When @Lock(WRITE) is used with time > 0, LockInterceptor tries rwl.writeLock().tryLock(time, unit); if the lock is not obtained within that time it throws LockException. The write lock is held by another thread for longer than the configured timeout, so the guarded business method could not run.

Source

Thrown at independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/LockInterceptor.java:61

        long time = lock.time();
        int readHoldCount = rwl.getReadHoldCount();
        boolean locked = false;

        try {
            if (readHoldCount > 0) {
                rl.lock();
            }
            try {
                if (readHoldCount > 0) {
                    // Release all read locks hold by the current thread before acquiring the write lock
                    for (int i = 0; i < readHoldCount; i++) {
                        rwl.readLock().unlock();
                    }
                }
                if (time > 0) {
                    locked = rwl.writeLock().tryLock(time, lock.unit());
                    if (!locked) {
                        throw new LockException("Write lock not acquired in " + lock.unit().toMillis(time) + " ms");
                    }
                } else {
                    rwl.writeLock().lock();
                    locked = true;
                }
            } finally {
                if (readHoldCount > 0) {
                    rl.unlock();
                }
            }
            return ctx.proceed();
        } finally {
            if (locked) {
                if (readHoldCount > 0) {
                    // Re-aqcquire the read locks
                    for (int i = 0; i < readHoldCount; i++) {
                        rwl.readLock().lock();
                    }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Increase lock.time()/unit on the @Lock annotation to a realistic bound.
  2. Shrink the work performed inside the write-locked method (move slow I/O outside the lock).
  3. Investigate the competing holder — log or dump threads to find a deadlock or long read-holders.
  4. Avoid read→write lock upgrade patterns (release the read lock before requesting write).
  5. If unbounded waiting is acceptable, set time = 0 so writeLock().lock() blocks indefinitely instead of throwing.

Example fix

// before
@Lock(value = LockType.WRITE, time = 100, unit = TimeUnit.MILLISECONDS)
public void sync() { heavyNetworkCall(); }
// after
@Lock(value = LockType.WRITE, time = 5, unit = TimeUnit.SECONDS)
public void sync() { heavyNetworkCall(); }
Defensive patterns

Strategy: retry

Validate before calling

// size the timeout to worst-case work: measure the write path before fixing lock.time()
long measuredMs = measure(writeOperation);
if (measuredMs >= unit.toMillis(time)) { log.warn("@Lock(WRITE) time too small: " + measuredMs + "ms"); }

Try / catch

try {
    return bean.writeOperation();
} catch (LockException e) {
    // bounded wait expired: back off and retry or degrade
    Thread.sleep(retryBackoffMs);
    return bean.writeOperation();
}

Prevention

When it happens

Trigger: Method annotated @Lock(value = WRITE, time = N, unit = X) while another thread holds (or waits on) the same bean's write/read lock longer than N units; time > 0 makes the wait bounded and fails fast instead of blocking forever.

Common situations: Long-running write operations under high concurrency; deadlock/livelock between read and write callers; time set too low for slow I/O inside the locked method; same bean called re-entrantly from a thread already holding the read lock (readers cannot upgrade to writer).

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/20b8fd8a0a191a75. Report an issue: GitHub.