Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Spring @Cacheable sync: collapse a local same-key cache miss

Last updated: 30 Sept 20264 min read
tutorial
IntermediateBy AITrove Editorial

A synchronized cache load asks the configured cache provider to compute one value for concurrent calls with the same key.

Download Spring source kit

The loader count is the proof

The source-kit context enables caching with ConcurrentMapCacheManager and obtains ReceiptLookup through the container. Two calls for R-41 return the same value while the method body loads once. R-42 triggers a second load. The test checks the count; a cache-hit response without a count could hide duplicate work.

The key must include every input that changes the result, including tenant scope where records differ. Tenant cache keys cover that boundary. sync=true depends on provider support and applies at that provider's scope. This in-process manager cannot coordinate two replicas. It also does not supply expiry, capacity limits or distributed invalidation.

Cold misses are not free

The callers waiting for a same-key load still consume request time and may exhaust upstream timeouts. A slow loader needs its own timeout and failure handling. If the loader fails, decide whether failures are cached, retried or surfaced; this fixture only checks successful values. Matched eviction matters after a write changes the underlying receipt.

Checked source

Java
@Cacheable(cacheNames = "receiptLookup", sync = true)
public String find(String receiptId) {
    loads.incrementAndGet();
    return "receipt:" + receiptId;
}

Verification boundary

SynchronizedCacheContractTest.concurrentCallsForOneKeyUseOneLocalLoader runs in the downloadable Spring source kit. The excerpt omits imports and surrounding setup; the kit contains the complete tests.

Costs and limits

The map lookup is expected O(1) average time in this local provider, with memory proportional to distinct retained keys. The test checks two same-key calls and one different key; it does not measure contention, TTL, cross-instance coordination or failure caching.

Common Mistakes

  • Do not assume sync=true is a distributed lock.
  • Do not omit tenant or representation inputs from the cache key.
  • Do not call a cache miss cheap when the loader is slow or unbounded.

Read next

Spring cache keys: separate tenants and test the loader count, Spring cache eviction: invalidate the same tenant key used by the read, Spring Boot metrics: bound tag values instead of tracking each receipt.

spring
spring-boot
cache-synchronized-loader
Storage details