A synchronized cache load asks the configured cache provider to compute one value for concurrent calls with the same key.
Spring @Cacheable sync: collapse a local same-key cache miss
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
@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.
