如何提高该 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);
}
如果你只是改变 hiScores
至ConcurrentHashMap
(并删除 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 - 我被你反直觉的方法名称欺骗了,在第一次尝试回答时没有查看第二个和第三个方法的代码。
<小时/>总结:
这件事比“还需要同步块(synchronized block)吗?”复杂得多。
如果您正在寻找通用答案或通用解决方案(即
HiScores
不是您的真实代码),您将找不到。正确性取决于实际需求和实际实现代码。
关于java - 高性能线程安全编码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51680560/