Concurrent HashMap 在多线程环境中表现不安全

23 浏览
0 Comments

Concurrent HashMap 在多线程环境中表现不安全

我有一个CHM\n

private ConcurrentHashMappR = new ConcurrentHashMap<>();

\n我有一个方法,它会将其值递增\n

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);
       }
    }

\n这个方法是通过jmeter从一个端点调用的,如果我同时发送500个请求,哈希映射保留的值不是500,而是437、430等,它的行为不是线程安全的,我们如何实现线程安全?

0
0 Comments

Concurrent HashMap not Behaving in thread Safe Manner(ConcurrentHashMap在多线程环境下不能保持线程安全的原因)

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

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

在你的情况下,如果一个线程在调用this.pR.get(count);之后,另一个线程在调用put之前也调用了它,它们将在更新对象方面存在竞争,并且似乎“丢失”了计数。

你需要在调用incrementPR时加上一些同步操作。

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

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

事实上,如果有同步操作,可能不需要使用同步映射。从提供的片段中无法确定这一点。

是的,我使用了同步,它运行得很好,但我希望有更好的方法,因为我觉得同步会对性能产生影响,并且虽然不明显,但当模型中包括其他变量时,它会反映出来。

在这种情况下,锁或同步哪个更好?

我提供了最简单的答案,但事实上,我建议使用锁。我认为在Java中,synchronized是一种不好的设计,你应该显式地声明和使用Lock对象。为每个对象提供一个监视器,并在此方法中膨胀(可能导致性能膨胀)是完全不必要的。在一个良好的实现中,你应该能够使用任何一种锁实现相同的性能,除非你需要尝试不同类型的锁,否则synchronized很快就会失败。

在重复标记中提到的链接在没有任何锁或同步的情况下工作

哪一个?其中一个是错误的,它们都使用了某种形式的同步。隐式或显式。我为你提供了最简单的安全解决方案。过早地进行优化是万恶之源。在你认为它是一个瓶颈之前,你不需要为一个简单的解决方案而苦恼。

那个可以工作并且有文档保证。是否更好取决于程序的配置文件,特别是负载和争用情况。在某些情况下(许多实际情况),它可能不具有最佳性能。与LongAdder相比,AtomicLong可能更适合一些情况。

0
0 Comments

Concurrent HashMap not Behaving in thread Safe Manner(Concurrent HashMap在多线程中无法保持线程安全的问题)

在某些语句中,您打破了“获取当前值”、“增加它”和“将其保存回映射”的步骤。当这些语句并发运行时,你得到了奇怪的结果。您的失败与并发映射无关。您应该为您的代码使用一些并发控制机制(如信号量、锁等)。有关更多信息,请参考以下问题:

Java Concurrency Incrementing a Value

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

AtomicInteger atomicInteger = new AtomicInteger();
// 当您想要添加您的数字时,请使用以下代码
atomicInteger.getAndAdd(1);

但是,如果这个语句的负载很重,使用AtomicLong可能会成为一个瓶颈(因为它使用比较和交换的CPU指令)。在这种情况下,最好使用LongAdder

LongAdder longAdder = new LongAdder();
// 当您想要添加您的数字时,请使用以下代码
longAdder.increment()

你是在说同步吗?有没有其他更好的方法?

在预期输入为整数的映射中,只需将映射声明为Map<您的键类型,LongAdder>,现在在需要增加值时使用map.get(myKey).increment()即可。

如果没有键存在,它能以线程安全的方式插入键吗?

我假设您的键是指标,在这种情况下,您可以使用上述的映射来拥有许多线程安全的计数器:map.get("numberOfX").increment()map.get("numberOfY").increment()等等。

0