Fra*_*jas 6 java concurrency multithreading
我正在使用 ConcurrentHashMap,在计算尚不存在的新元素时需要迭代其所有元素,并可能对同一映射进行一些其他修改。
我希望这些操作是原子的,并阻止 ConcurrentHashMap 以防止出现源自并发的异常。
我编程的解决方案是将 ConcurrentHashMap 对象与其自身同步作为锁,但是 Sonar 报告了一个重大问题,所以我不知道该解决方案是否正确
建议的代码:
对原文的修改
public class MyClass<K, V> {
ConcurrentHashMap<K, V> map = new ConcurrentHashMap<>();
public V get(K key) {
return map.computeIfAbsent(key, this::calculateNewElement);
}
protected V calculateNewElement(K key) {
V result;
// the following line throws the sonar issue:
synchronized(map) {
// calculation of the new element (assignating it to result)
// with iterations over the whole map
// and possibly with other modifications over the same map
}
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
此代码触发声纳主要问题:
多线程 - 在 util.concurrent 实例上执行同步
findbugs:JLM_JSR166_UTILCONCURRENT_MONITORENTER
此方法对作为 java.util.concurrent 包(或其子类)中的类的实例的对象执行同步。这些类的实例有自己的并发控制机制,这些机制与Java关键字synchronized提供的同步正交。例如,同步 AtomicBoolean 不会阻止其他线程修改 AtomicBoolean。
此类代码可能是正确的,但应仔细审查和记录,并且可能会使以后必须维护代码的人员感到困惑。
如果您必须为每次更新更改许多节点,则可能您使用了错误的数据结构。查看树的并发实现。持久性集合(提供不变性和快速更新)似乎是理想的选择。
ConcurrentHashMap 的构建是为了允许高度并发访问。(请参阅这篇描述其内部工作原理的文章)如果使用提供的方法(例如compute、computeIfPresent等)对条目进行更新,则应仅锁定条目所在的段,而不是整个事物。
当您锁定整个地图进行更新时,您将无法从使用这种专门的数据结构中受益。这就是声纳所抱怨的。
还有一个问题是读者也必须进行锁定,更新线程并不是唯一需要锁定的线程。这就是 CHM 最初被发明的原因。