Search code examples
javamultithreadingatomicatomicinteger

Atomically update 2 Long values


Let's say I have the following class in Java:

class Record {
  
  String name;
  double count;
  long repeat;
  
  public Record(String name){
    this.name = name;
  }

  public synchronized void update(Record other){
    this.count = (other.count * other.repeat + this.count * this.repeat)/(other.repeat + this.repeat);
    this.repeat = this.repeat + other.repeat;
  }

Now I have a map of such records ConcurrentHashMap<String, Record> recordConcurrentHashMap;

and I want to create a thread-safe correct update function.

Currently I have done this:

static ConcurrentHashMap<String,Record> recordConcurrentHashMap;

public static void updateRecords(Record other){
    Record record = recordConcurrentHashMap.computeIfAbsent(other.name, Record::new);
    record.update(other);
}

I am having to keep the update function synchronized to achieve correctness.

Can I do this without synchronized using LongAdder or LongAccumulator?

I tried using those, but couldn't figure out how to achieve the complex calculation with them.


Solution

  • No, you can't, certainly not with those.

    What you might consider doing -- which would avoid the synchronized -- would be to make Record immutable and unmodifiable, and do something like

    class Record {
      final String name;
      final double count;
      final long repeat;
    
      public Record(String name){
        this.name = name;
      }
    
      private Record(String name, double count, long repeat) {
        this.name = name; this.count = count; this.repeat = repeat;
      }
    
      public Record combine(Record other){
        return new Record(
          name,
          other.count * other.repeat + this.count * this.repeat)
             /(other.repeat + this.repeat),
          repeat + other.repeat);
      }
    }
    
    public static void updateRecords(Record other){
      Record record = recordConcurrentHashMap.merge(
        other.name, other, Record::combine);
    }