4

我正在实现一个简单的缓存,缓存存储为 AtomicReference。

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

缓存对象应该(懒惰地)从数据库表中填充。

我提供了一种将缓存数据返回给调用者的方法,但是如果数据为空(即未加载),则代码需要从数据库中加载数据。为了避免同步,我想到了使用 compareAndSet() 方法:

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

以这种方式使用 compareAndSet 是否可以,即。将数据库调用作为原子操作的一部分?它比仅仅同步方法更好/更差吗?

非常感谢您的任何建议..

4

1 回答 1

5

您没有达到预期的行为。这个表达式:

cacheData.compareAndSet(null, getDataFromDatabase())

总是会先打电话getDataFromDatabase()。这意味着数据是否被缓存并不重要。如果是,您仍然调用数据库,但丢弃结果。缓存正在工作,但性能同样很差。

考虑一下:

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

它并不完美(getDataFromDatabase()开始时仍然可以多次调用),但稍后会按预期工作。我也Collections.unmodifiableMap()更早地移动了,这样您就不必一遍又一遍地包装同一张地图。

这给我们带来了更简单的实现(不需要synchronizedAtomicReference不需要):

private volatile Map<String, String> cacheData;

if(cacheData == null) {
  cacheData = unmodifiableMap(getDataFromDatabase());
}
return cacheData;
于 2012-10-20T20:45:10.193 回答