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;