Unblockable atom upgrade to immutable map

Given a Javaslang / Vavr immutable map and a function that updates this map:

private Map<Foo, Bar> myMap = HashMap.empty();

public void setBar(Foo foo, Bar bar) {
  myMap = myMap.put(foo, bar);
}

      

How can I ensure that two simultaneous calls setBar()

for different keys Foo

will both be marked for their updates?

// thread A
setBar(fooA, barA)

// thread B
setBar(fooB, barB)

      

There seems to be a risk that the calls will be interleaved in such a way that:

  • thread A receives {}

  • stream B receives {}

  • stream B computes {}

    + fooB -> barB

    ={(fooB -> barB)}

  • stream B sets myMap

    to{(fooB -> barB)}

  • thread Computes {}

    + fooA -> barA

    ={(fooA -> barA)}

  • thread A sets myMap

    to{(fooA -> barA)}

  • stream B is updated.

Using AtomicReference

, I came up with the following, more or less based on the methods ConcurrentStack

in the "Non-Blocking Algorithms" section of Java Concurrency in Practice .

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));
}

      

It is right? And if so, is this a good implementation I can get, or is there something simpler (like some Java 8 AtomicReference

API I'm missing that implements this pattern)?

+3


source to share


1 answer


Usage AtomicReference

in this case is good. You can use the shortcut method

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

      



instead of this. See the javadoc forAtomicReference.updateAndGet

. The default java implementation is exactly the same as yours in Java 8.

+1


source







All Articles