原子地更新2个Long值

huangapple go评论92阅读模式
英文:

Atomically update 2 Long values

问题

假设我在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;
  }
}

现在我有一个这样的记录映射:ConcurrentHashMap<String, Record> recordConcurrentHashMap;

我想创建一个线程安全的正确的更新函数。

目前我已经这样做了:

static ConcurrentHashMap<String, Record> recordConcurrentHashMap;

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

为了保证正确性,我必须保持update函数同步。

我能否在不使用synchronized的情况下,使用LongAdder或者LongAccumulator来实现?我尝试过这样做,但是无法理解如何用它们来实现这个复杂的计算。

英文:

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&lt;String, Record&gt; recordConcurrentHashMap;

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

Currently I have done this:

static ConcurrentHashMap&lt;String,Record&gt; 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.

答案1

得分: 3

不行,绝对不行,特别是使用那些方式。

你可以考虑采取以下做法,这将避免使用synchronized,即将Record设为不可变和不可修改,然后进行类似以下操作:

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);
}
英文:

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

huangapple
  • 本文由 发表于 2020年8月28日 02:38:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/63622311.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定