美文网首页
关于ConcurrentHashMap的线程安全

关于ConcurrentHashMap的线程安全

作者: 矮子阿冰 | 来源:发表于2020-04-01 12:29 被阅读0次

在看SimpleAliasRegistry类的代码发现,在添加别名过程中会对ConcurrentHashMap上锁

public void registerAlias(String name, String alias) {
        Assert.hasText(name, "'name' must not be empty");
        Assert.hasText(alias, "'alias' must not be empty");
               #对存储别名的map加锁
        synchronized (this.aliasMap) {
            if (alias.equals(name)) {
                this.aliasMap.remove(alias);
                if (logger.isDebugEnabled()) {
                    logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
                }
            }
            else {
                String registeredName = this.aliasMap.get(alias);
                if (registeredName != null) {
                    if (registeredName.equals(name)) {
                        // An existing alias - no need to re-register
                        return;
                    }
                    if (!allowAliasOverriding()) {
                        throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +
                                name + "': It is already registered for name '" + registeredName + "'.");
                    }
                    if (logger.isDebugEnabled()) {
                        logger.debug("Overriding alias '" + alias + "' definition for registered name '" +
                                registeredName + "' with new target name '" + name + "'");
                    }
                }
                checkForAliasCircle(name, alias);
                this.aliasMap.put(alias, name);
                if (logger.isTraceEnabled()) {
                    logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
                }
            }
        }
    }

当时不理解既然ConcurrentHashMap是线程安全的为什么还要加锁?
加锁的目的是为了防止alias和name的重复引用 。参考资料https://cloud.tencent.com/developer/article/1497582

自己产生疑惑的原因是,对ConcurrentHashMap的理解不够深入,只知道是线程安全的解决了HashMap在扩容过程造成的闭环问题。并没有深入的理解ConcurrentHashMap提供了那些原子操作。
put,remove都会对key的Hash值节点进行上锁,保证了这两个操作的原子性。
get方法没有上锁,通过对node节点内的key,value加上volatile实现避免脏读。
所以这些操作在单独来说是线程安全具有原子性的,但是如果对他们进行组合操作或者多线程操作,就会出现线程不安全的情况。
举个先get再put的例子

public static void main(String[] args) throws InterruptedException {
        final ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<String, Integer>();
        map.put("key", 0);
        ExecutorService executorService = Executors.newFixedThreadPool(100);
        for (int i = 0; i < 1000; i++) {
            executorService.execute(new Runnable() {
                public void run() {
                  # synchronized (map){  对map进行上锁才能保证数据准确
                    int key = map.get("key") + 1;
                    map.put("key", key);
                    System.out.println(key);
                #}
                }
            });
        }
        Thread.sleep(3000); //模拟等待执行结束
        System.out.println("------" + map.get("key") + "------");
        executorService.shutdown();
    }

参考资料:
【小家Spring】分享Spring中一个小巧而优雅的类SimpleAliasRegistry源码分析
ConcurrentHashMap 多线程并发对值+1 总数不对
ConcurrentHashMap源码分析(JDK8版本)

相关文章

网友评论

      本文标题:关于ConcurrentHashMap的线程安全

      本文链接:https://www.haomeiwen.com/subject/kcvouhtx.html