如何提高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();


如果您在没有外部同步的情况下执行任何这些操作,那么它们将不是原子的。它们绝对不会是原子的序列...该方法需要。

不幸的是,我认为没有getHiScoresresetScores仅使用ConcurrentHashMap而不使用synchronized的解决方案。也可以使用AtomicReference,但这取决于对方法要求的属性的精确(例如形式/数学)规范。

1-我被您的违反直觉的方法名称所欺骗,并且在我第一次尝试回答时就没有看第二和第三方法的代码。



综上所述:


这些东西比“还需要同步块吗?”复杂得多。
如果您要寻找通用答案或通用解决方案(即HiScores不是您的真实代码),将找不到答案。正确性将取决于实际要求和实施的实际代码。

10-07 13:39