如何提高Java代码的性能?
public class HiScores {
private final Map<String, AtomicInteger> hiScores = new HashMap<>();
public long setHighest(String player, int newScore){
AtomicInteger highest;
synchronized(hiScores){
highest=hiScores.get(player);
if(highest==null){
highest=new AtomicInteger(0);
hiScores.put(player,highest);
}
}
int score=Math.max(highest.intValue(), newScore);
highest.set(score);
return score;
}
public Map<String, AtomicInteger> getHiScores(){
Map<String, AtomInteger> copy;
synchronized(hiScores){
copy=new HashMap<>(hiScores);
hiScores.clear();
}
return copy;
}
public void resetScores(){
synchronized(hiScores){
hiScores.clear();
}
}
}
如果将HashMap替换为ConurrentHashMap,是否仍需要同步块?
答案 0 :(得分:1)
如果将HashMap替换为ConcurrentHashMap,是否仍需要同步块?
如果您还不使用computeIfAbsent
(或类似名称),则确实需要它们。您需要自动执行以下顺序:
highest = hiScores.get(player);
if (highest == null) {
highest = new AtomicInteger(0);
hiScores.put(player, highest);
}
如果您仅将hiScores
更改为ConcurrentHashMap
(并删除synchronized
块),则存在争用条件,其中两个线程更新同一条目并同时更新两个线程将创建两个不同的AtomicInteger
对象……。第一个高分将丢失。
这里还有另一个比赛条件:
int score = Math.max(highest.intValue(), newScore);
highest.set(score);
单独使用setHighest
方法可以实现,而无需使用synchronized
...,但是您必须对代码进行重大更改。
其他方法也有问题 1 。
copy = new HashMap<>(hiScores);
hiScores.clear();
如果您在没有外部同步的情况下执行任何这些操作,它们将不是原子的。它们绝对不是序列的原子……该方法需要。
不幸的是,我认为没有getHiScores
或resetScores
仅使用ConcurrentHashMap
而不使用synchronized
的解决方案。也可以使用AtomicReference
,但这取决于方法要求的属性的精确(例如形式/数学)规范。
1-我被您的违反直觉的方法名称所欺骗,并且在我第一次尝试回答时就没有看第二方法和第三方法的代码。
总结:
这些东西比“还需要同步块吗?”要复杂得多。
如果您正在寻找通用答案或通用解决方案(即HiScores
不是您的真实代码),则找不到任何答案。正确性取决于实现的 actual 要求和 actual 代码。