繁体   English   中英

无锁原子更新到不可变Map

[英]Lock-free atomic update to immutable Map

给定一个Javaslang / Vavr 不可变映射 ,以及一个更新该映射的函数:

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)

似乎存在调用将被交错的风险:

  1. 线程A获取{}
  2. 线程B获得{}
  3. 线程B计算{} + fooB -> barB = {(fooB -> barB)}
  4. 线程B将myMap设置为{(fooB -> barB)}
  5. 线程A计算{} + fooA -> barA = {(fooA -> barA)}
  6. 线程A将myMap设置为{(fooA -> barA)}
  7. 线程B的更新丢失

使用AtomicReference ,我或多或少地基于Java Concurrency in Practice的“Nonblocking Algorithms”部分中的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)?

在这种情况下,使用AtomicReference很好。 您可以使用快捷方式

public void setBar(Foo foo, Bar bar) {
    myMap.updateAndGet(map -> map.put(foo, bar)));
}

代替。 请参阅AtomicReference.updateAndGetjavadoc 默认的Java实现与Java 8中的完全相同。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM