java - 使用 AtomicReference.compareAndSet 设置对数据库调用结果的引用是否合适?

标签 java java.util.concurrent compare-and-swap

我正在实现一个简单的缓存,并将缓存存储为 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 是否可以,即。将数据库调用作为原子操作的一部分?它比仅同步方法更好/更坏吗?

非常感谢任何建议..

最佳答案

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

cacheData.compareAndSet(null, getDataFromDatabase())

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

考虑一下:

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

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

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

private volatile Map<String, String> cacheData;

if(cacheData == null) {
  cacheData = unmodifiableMap(getDataFromDatabase());
}
return cacheData;

关于java - 使用 AtomicReference.compareAndSet 设置对数据库调用结果的引用是否合适?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12992478/

相关文章:

c++ - 为什么自由函数和成员函数都存在用于比较和交换操作?

c++ - memory_order_relaxed 和原子 RMW 操作

java - 为什么 Netty 4 "proxy"示例必须将 channel "AUTO_READ"设置为 false

java - 同步块(synchronized block)可以比 Atomics 更快吗?

java - 具有约束的 Java 中的并发请求处理

java - 将参数传递给 Java.util.Concurrent 中的 Call 方法

c - 为什么 GCC 填充这个位域?

java - "Key-Value Coding"用于 Java

javascript - 从 Java 的 HTML 输入发送多个文件

java - 使用 Netbeans 表单时出现通用 "Link Error"