如何提高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,是否仍需要同步块?
最佳答案
如果将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
不是您的真实代码),将找不到答案。正确性将取决于实际要求和实施的实际代码。