震惊!ConcurrentHashMap里面也有死循环,作者留下的“彩蛋”了解一下? (3)

简介: 震惊!ConcurrentHashMap里面也有死循环,作者留下的“彩蛋”了解一下? (3)

钓鱼执法


为什么我在文章的一开始就说了这是 Doug Lea 在钓鱼执法呢?


因为在最开始提问的艺术那一部分,我相信,Doug Lea 跑完那个测试案例之后,心里也有点数了。


大概知道问题在哪了,而且从他的回答和他写的文档中我也有理由相信,他写的这个方法的时候就知道可能会出问题。


而且,Pardeep 的回复中提到了文档,那我们就去看看官方文档对于该方法的描述是怎样的:


https://docs.oracle.com/javase/8/docs/api/


文档中说函数方法应该简短,简单。而且不能在更新的映射的时候更新映射。就是说不能套娃。


套娃,用程序说就是recursive(递归),按照文档说如果存在递归,则会抛出 IllegalStateException 。


而提到递归,你想到了什么?


我首先就想到了斐波拉契函数。我们用 computeIfAbsent 实现一个斐波拉契函数如下:


public class Test {
static Map<Integer, Integer> cache = new ConcurrentHashMap<>();
    public static void main(String[] args) {
        System.out.println("f(" + 14 + ") =" + fibonacci(14));
    }
    static int fibonacci(int i) {
        if (i == 0)
            return i;
        if (i == 1)
            return 1;
        return cache.computeIfAbsent(i, (key) -> {
            System.out.println("Slow calculation of " + key);
            return fibonacci(i - 2) + fibonacci(i - 1);
        });
    }
}


这就是递归调用,我用 JDK 1.8 跑的时候并没有抛出 IllegalStateException,只是程序假死了,原因和我们前面分析的是一样一样的。我理解这个地方是和文档不符的。


所以,我怀疑是 Doug Lea 在这个地方钓鱼执法。


CHM一定线程安全吗?


既然都说到 currentHashMap(CHM)了,那我说一个相关的注意点吧。


首先 CHM 一定能保证线程安全吗?


是的,CHM 本身一定是线程安全的。但是,如果你使用不当还是有可能会出现线程不安全的情况。


给大家看一点 Spring 中的源码吧:


org.springframework.core.SimpleAliasRegistry

在这个类中,aliasMap 是 ConcurrentHashMap 类型的:


在 registerAlias 和 getAliases 方法中,都有对 aliasMap 进行操作的代码,但是在操作之前都是用 synchronized 把 aliasMap 锁住了。


为什么?为什么我们操作 ConcurrentHashMap 的时候还要加锁呢?


这个是根据场景而定的,这个别名管理器,在这里加锁应该是为了避免多个线程操作 ConcurrentHashMap 。


虽然 ConcurrentHashMap 是线程安全的,但是假设如果一个线程 put,一个线程 get,在这个代码的场景里面是不允许的。


如果觉得不太好理解的话我举一个 redis 的例子。


redis 的 get、set 方法都是线程安全的吧。但是你如果先 get 再 set,那么在多线程的情况下还是会有问题的。


因为这两个操作不是原子性的。所以 incr 就应运而生了。


我举这个例子的是想说线程安全与否不是绝对的,要看场景。给你一个线程安全的容器,你使用不当还是会有线程安全的问题。


再比如,HashMap 一定是线程不安全的吗?


说不能说的这么死吧。它是一个线程不安全的容器。但是如果我的使用场景是只读呢?

在这个只读的场景下,它就是线程安全的。


总之,看场景。道理,就是这么一个道理。


最后说两句(求关注)


所以点个“赞”吧,周更很累的,不要白嫖我,需要一点正反馈。


才疏学浅,难免会有纰漏,如果你发现了错误的地方,还请你留言指出来,我对其加以修改。


感谢您的阅读,我坚持原创,十分欢迎并感谢您的关注。


我是 why,一个被代码耽误的文学创作者,不是大佬,但是喜欢分享,是一个又暖又有料的四川好男人。


欢迎关注我的微信公众号:why技术。在这里我会分享一些java技术相关的知识,用匠心敲代码,对每一行代码负责。偶尔也会荒腔走板的聊一聊生活,写一写书评、影评。感谢你的关注,愿你我共同进步。

目录
相关文章
|
5月前
|
存储 Java 开发者
面试官:小伙子知道synchronized的优化过程吗?我:嘚吧嘚吧嘚,面试官:出去!
面试官:小伙子知道synchronized的优化过程吗?我:嘚吧嘚吧嘚,面试官:出去!
69 1
|
5月前
|
存储 缓存 安全
面试官:小伙子,能聊明白JMM给你SSP!我:嘚吧嘚吧一万字,直接征服面试官!
面试官:小伙子,能聊明白JMM给你SSP!我:嘚吧嘚吧一万字,直接征服面试官!
47 1
|
存储 缓存 安全
Java并发编程73道面试题及答案 —— 这也太棒了(一)
Java并发编程73道面试题及答案 —— 这也太棒了
|
安全 算法 Java
Java并发编程73道面试题及答案 —— 这也太棒了(三)
Java并发编程73道面试题及答案 —— 这也太棒了
|
存储 安全 算法
Java并发编程73道面试题及答案 —— 这也太棒了(二)
Java并发编程73道面试题及答案 —— 这也太棒了
|
算法 C++
【每日算法Day 73】学妹大半夜私聊我有空吗,然后竟然做出这种事!
【每日算法Day 73】学妹大半夜私聊我有空吗,然后竟然做出这种事!
|
Java 程序员
学妹问我Java异常是怎么回事,讲了半夜才明白,速度收藏!!!记得点赞和关注
异常是Java开发中常见的,也是程序最不愿意看到的,因为有异常基本上就代表我们写的代码有bug,很烦,游戏服务端有异常上报系统,每当半夜收到异常上报都慌的一笔。今天就扒一扒异常,开始走起。
146 0
学妹问我Java异常是怎么回事,讲了半夜才明白,速度收藏!!!记得点赞和关注
|
前端开发 Java 测试技术
如何啃下JVM这座大山,完结撒花!(三)
JVM的学习轨迹,可以先通过该文章学习,然后对照《深入理解Java虚拟机》书籍把重点知识过一遍,最后最好能实战一下
115 1
|
存储 运维 监控
如何啃下JVM这座大山,完结撒花!(二)
JVM的学习轨迹,可以先通过该文章学习,然后对照《深入理解Java虚拟机》书籍把重点知识过一遍,最后最好能实战一下
148 0
如何啃下JVM这座大山,完结撒花!(二)
|
算法 前端开发 Java
如何啃下JVM这座大山,完结撒花!(一)
JVM的学习轨迹,可以先通过该文章学习,然后对照《深入理解Java虚拟机》书籍把重点知识过一遍,最后最好能实战一下
141 0
如何啃下JVM这座大山,完结撒花!(一)