concurrenthashmap删除方法线程安全性

sqougxex  于 2021-08-25  发布在  Java
关注(0)|答案(2)|浏览(422)

我试图浏览spring源代码(5.2.8.release),并找到以下代码。

package org.springframework.core;

public class SimpleAliasRegistry implements AliasRegistry {
    /**Map from alias to canonical name. */
    private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);

    @Override
    public void removeAlias(String alias) {
        synchronized (this.aliasMap) {     // what if we remove such synchronized line ?
            String name = this.aliasMap.remove(alias);
            if (name == null) {
                throw new IllegalStateException("No alias '" + alias + "' registered");
            }
        }
    }
}

但是我不确定的是为什么removealias方法中有一个synchronized关键字,它真的有必要吗?如果我们删除synchronized关键字呢?会发生什么?
这是我的想法。 ConcurrentHashMap 当我们调用它提供的方法时应该是线程安全的,比如 put , getremove . 我们需要使用 synchronized 只有在这里执行多个操作时才锁定对象,例如先获取,然后放置或移除。但我们想让区块不受干扰地运行。
是我的想法错了,还是Spring有什么原因 removeAlias 方法就是这样设计的,非常感谢。

更新

我还发现了它被更新的时间,开发者故意这样做,在修复问题时, SimpleAliasRegistry registerAlias not atomic ,这是他写出来的原因。
我通过同步保护registeralias和removealias,允许现有的synchronized ResolveAlias方法和其他方法可靠地查看一致状态。
然而,我只是认为在registeralias中同步是必要的,但仍然不能说服人们为什么需要这样做 synchronized 在removealias方法中,有人能给我解释一下吗?
资料来源:https://github.com/spring-projects/spring-framework/issues/21119 [问题]
资料来源:https://github.com/spring-projects/spring-framework/commit/1b1a69a144f657d46c752f1c017f64d3302891d2 [该问题的变化]

eaf3rand

eaf3rand1#

使用synchronized onconcurrenthashmap就像取消concurrenthashmap的使用。因此,在这种情况下,具有synchronized的hashmap是相同的。
同步的要点是锁定整个Map。concurrenthashmap的实现不需要锁定整个Map,因为它提供了段锁,在Concurrent访问期间自动锁定concurrenthashmap的一小部分。
也许这个项目有一个bug,op通过锁定整个Map找到了一个快速修复方法。
再检查一下这个问题,我认为op想要在Map级别(get put)上使java方法成为原子的,并且担心java方法不会像预期的那样运行,所以它向前推进并在整个Map的任何地方同步。正如他所写的,他也可以利用concurenthashmap的compute(..)、ComputeFabSent(..)、computeifpresent(..)方法来避免这种情况,但我认为他采取了快速同步整个Map的方法。
他还可以在选择修复后将concurenthashmap转换为hashmap,因为他取消了concurenthashmap的主要用法。
在这里也看一看(所以线程),了解op为什么一直在与这个问题斗争。

dvtswwa3

dvtswwa32#

在我看来:registeralias/getalias都使用同步锁定这个Map。如果没有同步的removealias方法,可能会出现这种情况:在调用this.aliasmap.remove后的removealias中,它已成功删除别名,但removealias未完成,现在其他线程调用registeralias在该Map中放置相同的别名。因此,removealias不能成功执行。在removealias internal中有不同的数据

相关问题