【发布时间】:2017-05-24 01:57:37
【问题描述】:
给定一个 Javaslang / Vavr immutable map,以及一个更新该映射的函数:
private Map<Foo, Bar> myMap = HashMap.empty();
public void setBar(Foo foo, Bar bar) {
myMap = myMap.put(foo, bar);
}
如何确保针对不同的 Foo 密钥对 setBar() 的两个并发调用都会记录其更新?
// thread A
setBar(fooA, barA)
// thread B
setBar(fooB, barB)
似乎存在调用交错的风险:
- 线程A得到
{} - 线程 B 得到
{} - 线程 B 计算
{}+fooB -> barB={(fooB -> barB)} - 线程 B 将
myMap设置为{(fooB -> barB)} - 线程 A 计算
{}+fooA -> barA={(fooA -> barA)} - 线程 A 将
myMap设置为{(fooA -> barA)} - 线程 B 的更新丢失
使用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 8 AtomicReference API)?
【问题讨论】:
标签: java immutability atomic vavr