【问题标题】:Concurrent HashMap not Behaving in thread Safe Manner [duplicate]并发 HashMap 不以线程安全方式运行 [重复]
【发布时间】:2017-06-17 21:16:53
【问题描述】:

我有一个 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);
       }
    }

如果我触发 500 个并发请求,则使用 jmeter 从端点调用此方法,哈希映射孔的值不是 500,而是 437、430 等,它的行为不是线程安全的,我们如何实现线程安全性

【问题讨论】:

  • ConcurrentHashMap 不保证操作序列是原子的。
  • 那么让hashmap线程安全同步是唯一的方法吗?

标签: java multithreading hashmap


【解决方案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()

【讨论】:

  • 你说的是同步的吧?还有其他更好的方法吗
  • 如何在需要整数作为输入的地图中实现这一点?
  • 只需将 map 声明为 Map&lt;TypeOfYourKey,LongAdder&gt; 现在在需要增加值时使用 map.get(myKey).increment()
  • 如果没有密钥,它会以线程安全的方式插入密钥
  • 我想你的键是你的指标,在​​这种情况下,你可以有许多线程安全的计数器,只需使用提到的映射:map.get("numberOfX").increment();map.get("numberOfY").increment() 等等。
【解决方案2】:

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

这并不意味着它将确保另一个类不能在调用之间修改它。

在您的情况下,如果一个线程调用 this.pR.get(count); ,然后另一个线程在调用 put 之前调用它,那么它们将在竞争中更新对象,并且看起来“丢失”计数。

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

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

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

事实上,在那里同步可能没有必要使用同步地图。从提供的 sn-p 中并不清楚。

【讨论】:

  • 是的,我使用了同步,它工作正常,我希望有一些更好的方法,因为我觉得同步会导致性能影响,虽然不明显,但当模型中包含其他变量时它会反映跨度>
  • 在这种情况下哪个更好的锁定或同步?
  • @Rahul 我提供了最简单的答案,但实际上我会推荐一把锁。我相信 synchronized 在 Java 中是一个糟糕的设计,您应该明确声明和使用 Lock 对象。为每个对象提供一个监视器和这样做的方法膨胀(以及可能的性能膨胀)是完全没有必要的。在一个好的实现中,您应该能够获得相同的性能,除非您需要尝试锁定类型,在这种情况下 synchronized 很快就会失败。
  • 复制中提到的链接标记工作没有任何锁定或同步
  • @Rahul 哪一个?其中一个坏了,它们都使用某种同步。隐式或显式。我在为你提议最短的安全路线。过早的优化是万恶之源。除非您认为这是一个瓶颈,否则我不会为简单的解决方案出汗。
猜你喜欢
  • 1970-01-01
  • 2020-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-01
  • 2011-08-30
相关资源
最近更新 更多