java - 高性能线程安全编码

标签 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,还需要同步块(synchronized block)吗?

最佳答案

Are the synchronized blocks still required if the HashMap was replaced by a ConcurrentHashMap?

如果您不使用 computeIfAbsent,则确实需要它们(或类似)。您需要原子地执行此序列:

  highest = hiScores.get(player);
  if (highest == null) {
      highest = new AtomicInteger(0);
      hiScores.put(player, highest);
  }

如果你只是改变 hiScoresConcurrentHashMap (并删除 synchronized block ),然后存在竞争条件,两个线程更新同一条目并且同时将创建两个不同的 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 - 我被你反直觉的方法名称欺骗了,在第一次尝试回答时没有查看第二个和第三个方法的代码。

<小时/>

总结:

  1. 这件事比“还需要同步块(synchronized block)吗?”复杂得多。

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

关于java - 高性能线程安全编码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51680560/

相关文章:

java - UDP套接字和多个回复

java - 如何在Java中为Regexp Sql使用myPreparedStmt.setString?

java - 使用 Apache Poi 如何创建多值电子表格单元格,以便在 MS Excel 中正确显示,而不仅仅是在 OpenOffice 中

c# - 竞争条件使 nHibernate 创建重复条目

c - C 中的 3 个线程之间交替

ruby-on-rails - Rails,find_by().present 存在吗?比 where().exists 性能更高?

java - 使用 jpa 从 postgres 读取 byte[] 时长度几乎翻倍

android - 我的 "MyException"显示 Toast 在抛出线程时会导致问题。我应该如何重新组织异常处理?

.net - 其中一个是否比另一个使用更多的资源?

css - * css 选择器的实际性能影响是什么?