给定Javaslang / Vavr immutable map,以及更新该地图的函数:
private Map<Foo, Bar> myMap = HashMap.empty();
public void setBar(Foo foo, Bar bar) {
myMap = myMap.put(foo, bar);
}
如何确保针对不同setBar()
密钥的Foo
的两个并发呼叫都会记录其更新?
// thread A
setBar(fooA, barA)
// thread B
setBar(fooB, barB)
似乎存在调用交错的风险:
{}
{}
{}
+ fooB -> barB
= {(fooB -> barB)}
myMap
设置为{(fooB -> barB)}
{}
+ fooA -> barA
= {(fooA -> barA)}
myMap
设置为{(fooA -> barA)}
使用AtomicReference
,我或多或少地根据Java Concurrency in Practice的“非阻止算法”部分中的ConcurrentStack
方法提出了以下内容。
private AtomicReference<Map<Foo, Bar>> myMap =
new AtomicReference<>(HashMap.empty());
public void setBar(Foo foo, Bar bar) {
Map<Foo, Bar> myMap0;
Map<Foo, Bar> myMap1;
do {
myMap0 = myMap.get();
myMap1 = myMap0.put(foo, bar);
} while (!myMap.compareAndSet(myMap0, myMap1));
}
这是对的吗?如果是这样,它是否是我可能获得的良好实现,或者是否有更简单的东西(例如,我缺少一些实现此模式的Java AtomicReference
API)?
答案 0 :(得分:1)
在这种情况下使用AtomicReference
是好的。您可以使用快捷方式
public void setBar(Foo foo, Bar bar) {
myMap.updateAndGet(map -> map.put(foo, bar)));
}
代替。请参阅javadoc for AtomicReference.updateAndGet
。默认的Java实现与Java 8中的实现完全相同。