mybatis/mybatis-3 · error · CacheException

Got interrupted while trying to acquire lock for key {key}

Error message

Got interrupted while trying to acquire lock for key {key}

What it means

Thrown by BlockingCache.acquireLock() when the thread waiting on a key's CountDownLatch is interrupted while blocked. Unlike the timeout case this is a thread-lifecycle event (shutdown, thread pool interrupt, test harness interruption), and the original InterruptedException is chained as the cause so the interrupt status and context are preserved.

Source

Thrown at src/main/java/org/apache/ibatis/cache/decorators/BlockingCache.java:107

  private void acquireLock(Object key) {
    CountDownLatch newLatch = new CountDownLatch(1);
    while (true) {
      CountDownLatch latch = locks.putIfAbsent(key, newLatch);
      if (latch == null) {
        break;
      }
      try {
        if (timeout > 0) {
          boolean acquired = latch.await(timeout, TimeUnit.MILLISECONDS);
          if (!acquired) {
            throw new CacheException(
                "Couldn't get a lock in " + timeout + " for the key " + key + " at the cache " + delegate.getId());
          }
        } else {
          latch.await();
        }
      } catch (InterruptedException e) {
        throw new CacheException("Got interrupted while trying to acquire lock for key " + key, e);
      }
    }
  }

  private void releaseLock(Object key) {
    CountDownLatch latch = locks.remove(key);
    if (latch == null) {
      throw new IllegalStateException("Detected an attempt at releasing unacquired lock. This should never happen.");
    }
    latch.countDown();
  }

  public long getTimeout() {
    return timeout;
  }

  public void setTimeout(long timeout) {
    this.timeout = timeout;

View on GitHub (pinned to 008069adb1)

Solutions

  1. Restore the interrupt status in your catch block (Thread.currentThread().interrupt()) and treat the query as cancelled — do not retry blindly
  2. Avoid interrupting threads that may be inside mybatis cache waits; use cooperative cancellation (Future.cancel(false), flags)
  3. Tune blockingTimeout so waits are bounded and shutdown drains quickly

Example fix

// before
try { cache.getObject(key); } catch (CacheException e) { /* ignored */ }

// after
try {
  cache.getObject(key);
} catch (CacheException e) {
  if (e.getCause() instanceof InterruptedException) {
    Thread.currentThread().interrupt();
    throw new CancellationException("query interrupted", e);
  }
  throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

null

Try / catch

catch (CacheException e) { if (e.getCause() instanceof InterruptedException) { Thread.currentThread().interrupt(); cancelTask(); return; } throw e; }

Prevention

When it happens

Trigger: A thread waiting inside BlockingCache.getObject() for another thread's query to finish receives Thread.interrupt() — e.g. application shutdown draining executor threads, a servlet request timeout thread group interrupt, orJUnit/TimeboundUnit timeout teardown while a cache-blocking query is in flight.

Common situations: Graceful shutdown interrupts worker threads mid-query; async frameworks (WebFlux/CompletableFuture ondedicated pools) cancelling tasks; test harness timeouts interrupting blocked queries; misbehaving middleware interrupting threads it does not own.

Related errors


AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14). Data as JSON: /api/errors/88cce4792e6fe522. Report an issue: GitHub.