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

Java 使用AtomicReference.compareAndSet设置对数据库调用结果的引用是否合适?,java,java.util.concurrent,compare-and-swap,Java,Java.util.concurrent,Compare And Swap,我正在实现一个简单的缓存,缓存存储为原子引用 private AtomicReference<Map<String, String>> cacheData; 以这种方式使用compareAndSet(即将数据库调用作为原子操作的一部分)可以吗?这比仅仅同步方法好/坏吗 非常感谢您的建议。您没有达到预期的行为。这句话: cacheData.compareAndSet(null, getDataFromDatabase()) 将始终首先调用getDataFromDatab

我正在实现一个简单的缓存,缓存存储为原子引用

private AtomicReference<Map<String, String>> cacheData;
以这种方式使用compareAndSet(即将数据库调用作为原子操作的一部分)可以吗?这比仅仅同步方法好/坏吗


非常感谢您的建议。

您没有达到预期的行为。这句话:

cacheData.compareAndSet(null, getDataFromDatabase())
将始终首先调用
getDataFromDatabase()
。这意味着数据是否被缓存并不重要。如果是,您仍然调用数据库,但放弃结果。缓存正在工作,但性能同样很差

请考虑以下情况:

if(cacheData.get() == null) {
    cacheData.compareAndSet(null, unmodifiableMap(getDataFromDatabase()));
}
return cacheData.get());
它并不完美(仍然可以在开始时多次调用
getDataFromDatabase()
),但稍后将按预期工作。此外,我在前面移动了
Collections.unmodifiableMap()
,这样就不必反复包装同一个映射

这使我们可以实现更简单的实现(不需要
synchronized
AtomicReference
):

私有易失性映射缓存数据;
if(cacheData==null){
cacheData=unmodifiableMap(getDataFromDatabase());
}
返回缓存数据;

感谢您快速回复Tomasz,我非常感谢!好的,很好,我现在明白了,这不是一个好的模式!出于兴趣,您怎么知道getDataFromDatabase()会在空检查之前被调用?我在Javadoc中看不到这个方法。@MandyW:这就是Java的工作原理。参数是按值传递的(总是!),在我们进入方法之前必须对它们进行求值。在Scala中,您可以通过名称进行传递,从而避免了此问题。感谢您的选择。。这比同步getData()更可取吗?我真的看不到多少性能优势。@MandyW:通过说你看不到性能优势,你衡量了吗<代码>易失性通常应该比
同步
快得多,尤其是在高并发负载下。因此,如果对数据库的调用出现问题,例如等待一分钟左右,我实际上更考虑避免阻塞所有调用线程。。我认为使整个方法同步将意味着没有线程可以取得任何进展。。通过使用原子比较数据集的代码片段,我处于更好的位置吗?其他线程是否会在等待原子写入完成时被阻塞,或者它们是否都会单独继续调用getDataFromDatabase(),然后最终(假设db恢复正常)一个线程将成功设置cacheData?
if(cacheData.get() == null) {
    cacheData.compareAndSet(null, unmodifiableMap(getDataFromDatabase()));
}
return cacheData.get());
private volatile Map<String, String> cacheData;

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