Search code examples
javaatomicvolatilevavr

Vavr Set field should be volatile, atomic or declared other way?


In vavr you have the io.vavr.collection.Set that is immutable. What is a proper way and idiomatic way to use that considering that the addName() and names() could be called from various threads?

import io.vavr.collection.Set;
import io.vavr.collection.HashSet;
public class Names{
  public/*private*/ /**volatile*/ Set<String> names = HashSet.empty();
  public void addName(String name){
    names = names.add(name);
  }
  public Set<String> names(){
    return names;
  }
}

Should I use volatile? Should I use AtomicRef<Set<String>> instead?


Solution

  • I would use AtomicReference. See my answer to a similar question. Volatile is definitely not enough, because it only guarantees that updates to the variable will be visible to other threads immediately (it effectively disables cached access to it). Concurrent thread access will not be synchronized though, so it could happen that two threads build an updated Set concurrently, and one of the threads will overwrite the other threads change.

    Given two threads T1 and T2 that are running concurrently, imagine the following sequence of events:

    1. T1 reads variable, current state is V
    2. T2 reads variable, current state is V
    3. T1 calculates updated state V×U1
    4. T2 calculates updated state V×U2
    5. T1 updates variable to V×U1
    6. T2 updates variable to V×U2

    The final value from the above sequence will be V×U2, so the update U1 is effectively lost.

    AtomicReference on the other hand guarantees that the variable is updated atomically. You'll have to pass in the updater function to the AtomicReference, so it will be called before atomically storing the result. Make sure you are using a pure function without side effects as the updater function might be called multiple times in case the reference was updated atomically by another thread in the meanwhile.