Is it appropriate to use AtomicReference.compareAndSet to provide a link to the results of a database call?

I use a simple cache with a cache that is stored as an AtomicReference.

private AtomicReference<Map<String, String>> cacheData; 

The cache object must be populated (lazily) from the database table.

I provide a method for returning cache data to the caller, but if the data is null (i.e. not loaded), then the code should load the data from the database. To avoid synchronization, I thought about using the compareAndSet () method:

 public Object getCacheData() { cacheData.compareAndSet(null, getDataFromDatabase()); // atomic reload only if data not set! return Collections.unmodifiableMap(cacheData.get()); } 

Is it possible to use compareAndSet in this way, i.e. use a database call as part of an atomic action? Is this better / worse than just method synchronization?

Thanks so much for any advice.

+4
source share
1 answer

You have not reached the expected behavior. This expression:

 cacheData.compareAndSet(null, getDataFromDatabase()) 

will always call getDataFromDatabase() . This means that it doesn't matter if the data was cached or not. If so, you will still call the database, but discard the results. The cache works, but the performance is equally bad.

Consider this instead:

 if(cacheData.get() == null) { cacheData.compareAndSet(null, unmodifiableMap(getDataFromDatabase())); } return cacheData.get()); 

This is not ideal (still getDataFromDatabase() can be called several times at the beginning), but will work later, as expected. I also moved Collections.unmodifiableMap() earlier so you don't have to transfer the same map again and again.

This leads us to an even simpler implementation (no synchronized or AtomicReference ):

 private volatile Map<String, String> cacheData; if(cacheData == null) { cacheData = unmodifiableMap(getDataFromDatabase()); } return cacheData; 
+5
source

Source: https://habr.com/ru/post/1441014/


All Articles