Perfomant线程安全编码

时间:2018-08-03 22:00:43

标签: java multithreading performance concurrency

如何提高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,是否仍需要同步块?

1 个答案:

答案 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();

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

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

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


总结:

  1. 这些东西比“还需要同步块吗?”要复杂得多。

  2. 如果您正在寻找通用答案或通用解决方案(即HiScores不是您的真实代码),则找不到任何答案。正确性取决于实现的 actual 要求和 actual 代码。