ianaz ianaz - 2 months ago 33
Java Question

Spring cacheable not synchronized

I have a singleton class (@Service annotated). This class has a method which takes 200/300ms to execute.

This method is annotated with @Cacheable and synchronized.

@Cacheable(value="nextPlaying", key = "#startingFrom.getYear() + #startingFrom.getMonth() + #startingFrom.getDay() + #startingFrom.getHours() + #startingFrom.getMinutes() + #locale.getLanguage()")
public synchronized List<Match> getNextPlaying(Date startingFrom, Locale locale)


By launching multiple threads calling this method I see that for these 200/300ms until the result isn't cached, it executes again and again the method until is cached.
Seems that @Cacheable annotation doesn't take synchronized into account...
Is this a bug?

Answer

When you use the @Cacheable annotation, the code that implements the cache search is outside of your method. Therefore, the synchronized modifier does not affect it.

If you want all the threads to use the cached result, you should create a synchronized method that wraps the invocation to the cacheable getNextPlaying method. Something like this:

public synchronized List<Match> getNextPlayingSynchronized(Date startingFrom, Locale locale){
     return getNextPlaying(Date startingFrom, Locale locale);
}
...
@Cacheable(value="nextPlaying", key = "#startingFrom.getYear() + #startingFrom.getMonth() + #startingFrom.getDay() + #startingFrom.getHours() + #startingFrom.getMinutes() + #locale.getLanguage()")
public List<Match> getNextPlaying(Date startingFrom, Locale locale){
...//your old method without the synchronized modifier
}

It's important that these methods are in different classes. Otherwise, the aspects don't work.