簡體   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