并发HashMap不以线程安全方式表现

时间:2017-06-17 21:16:54

标签: java multithreading hashmap

我有一个CHM

private ConcurrentHashMap<Integer,Integer>pR = new ConcurrentHashMap<>();

我有一个增加其值的方法

public void incrementPR(int count){

        Integer value = this.pR.get(count);
       if(value == null){
           this.pR.put(count,1);
       } else {
           this.pR.put(count,value+1);
       }
    }

这个方法是使用jmeter从端点调用的,如果我触发500并发请求的值,即hashmap不是500但是437,430等它的线程安全方式没有表现,我们如何实现相同的安全性< / p>

2 个答案:

答案 0 :(得分:1)

在某些陈述中,你打破“获取当前值”并“增加它”并“将其保存回地图”。现在,当这些语句同时运行时,您会得到有线结果。您的失败与并发映射无关。您应该为代码使用一些并发控制机制(如信号量,锁...)。有关详细信息,请参阅此问题: Java Concurrency Incrementing a Value

如果您对有效的解决方案(不使用锁定机制)感兴趣,可以使用AtomicInteger

AtomicInteger atomicInteger = new AtomicInteger();
//when you want to add your number, use this code
atomicInteger.getAndAdd(1);

但是如果你对这个语句负载很重,那么使用AtomicLong可能是一个瓶颈(因为它使用了比较和交换cpu指令)。在这种情况下,最好将LongAdder用作:

LongAdder longAdder = new LongAdder();
//when you want to add your number, use this code
longAdder.increment()

答案 1 :(得分:0)

当一个类被描述为“线程安全”时。通常意味着该类将确保在其方法的并发调用之间有足够的排除来维护类完整性(以及相关的不变量)。

它的意思并不是说它会确保另一个班级不能在通话之间修改它。

在你的情况下,如果一个线程调用this.pR.get(count);然后另一个线程在调用put之前调用它,那么他们就会竞争哪个更新对象并且它似乎丢失& #39;计数。

您需要围绕对incrementPR的调用进行一些同步。

在这种情况下,简单而明显的答案是:

public synchronized void incrementPR(int count){
    //....
}

事实上,在同步时,可能没有必要使用同步映射。从提供的代码片段中可以清楚地看出这一点。