英文:
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<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.
答案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);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论