14

If a method marked @Cacheable takes 10 minutes to complete and two threads t1,t2 access the method.

t1 accesses at time 0 (cache method is now run for first time) t2 accesses at time t1+5mins

Does this mean that t2 will not access the data for approx 5 mins since t1 has already started the @Cacheable operation and it's due to complete in 5 mins(as its been running for 5 mins) or will a new call to @Cacheable be invoked by t2?

blue-sky
  • 51,962
  • 152
  • 427
  • 752
  • 4
    Support for synchronized caches is added in Spring 4.3: https://spring.io/blog/2016/03/04/core-container-refinements-in-spring-framework-4-3 – Thomas Apr 07 '16 at 12:21

4 Answers4

8

If the result of the first execution hasn't been cached, the second invocation will proceed.

You should understand that @Cacheable is centered around the content of the cache (and not specifically a thread's execution context [well, kind of; the cache still needs to be threadsafe]). On execution of a method, the cache is first checked to see if the key exists: if t1 is taking a while to complete, its result will not be cached therefore, concurrent executions will proceed without regard for t1's execution

kolossus
  • 20,559
  • 3
  • 52
  • 104
  • Which result will be cached? does the second thread's execution completion will override first cached result? – Usama Tariq Nov 16 '14 at 18:19
  • At least, for the ConcurrentMap-based cache, you should get the result of the first execution (going by basic map rules, if there's a value for the supplied key, the previous value is returned) @UsamaTariq – kolossus Nov 17 '14 at 05:12
  • 1
    When second thread came for execution there was no value in cache (since t1 takes a while to complete) therefore t2 will also start execution. As far as i understand result is cached after completion of execution. t1 will cache its results, but t2 will complete later. Shouldn't it override previous results? or will it check for existence before caching? – Usama Tariq Nov 17 '14 at 12:40
  • @UsamaTariq- my mistake in the ordering, but yes, the general principle should remain the same: if there's already value in a map for a given key, `put`ing to it will not override the existing value; you'll only get the existing value. Spring's cache already has structures for cache eviction, I wouldn't expect the cache population's policies to overlap the cache eviction policy – kolossus Nov 17 '14 at 14:34
  • 1
    @kolossus The first value should be overridden absolutely. After invoke the calculation, the put is used, not the putIfAbsent. – Loki Feb 03 '15 at 23:22
8

Since Spring 4.3, you can get the desired blocking behavior by adding the sync = true flag:

@Cacheable(value="cacheName", key="{#keyField1, #keyField2}", sync = true)
JayVeeInCorp
  • 144
  • 1
  • 3
  • 12
6

There is no blocking on @Cacheable.

But you can use blocking cache strategy in cache implementation. First query found miss has the responsibility to rebuild the cache. Others queries wait until the cache is rebuilt.

  • For local cache implementation, use ReadWriteLock. See the net.sf.ehcache.constructs.blocking.BlockingCache.
  • For remote cache implementation, use ghetto central lock.
Loki
  • 931
  • 8
  • 13
2

As colossus explained, the cache is checked prior to the method call. So, if the item is not in cache (as will be the case at t1 + 5 mins), the method invocation will happen for thread t2 as well.

There is no "blocking" on the @Cacheable annotation. t2 will call the method as if there was a cache-miss and hence t2 will also take 10 minutes to complete the same method.

Jigish
  • 1,764
  • 1
  • 15
  • 20