有时我们会提供糟糕的建议。 就像该文章中有关如何将Java 8用于缓存的功能性方法来计算斐波那契数的文章一样 。 正如我们的读者之一马蒂亚斯(Matthias)在评论中注意到的那样 ,提出的算法可能永远不会停止。 考虑以下程序:

public class Test {static Map<Integer, Integer> cache = new ConcurrentHashMap<>();public static void main(String[] args) {System.out.println("f(" + 25 + ") = " + fibonacci(25));}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);});}
}

它将至少在以下Java版本上无限期运行:

C:\Users\Lukas>java -version
java version "1.8.0_40-ea"
Java(TM) SE Runtime Environment (build 1.8.0_40-ea-b23)
Java HotSpot(TM) 64-Bit Server VM (build 25.40-b25, mixed mode)

这当然是“功能”ConcurrentHashMap.computeIfAbsent() Javadoc读取:

如果指定的键尚未与某个值关联,则尝试使用给定的映射函数计算其值,除非为null,否则将其输入此映射。 整个方法调用是原子执行的,因此每个键最多可应用一次该功能。 在进行计算时,可能会阻止其他线程对此映射进行的某些尝试的更新操作,因此计算应简短而简单, 并且不得尝试更新此映射的任何其他映射

尽管并非出于相同的并发原因,“不得”的措辞是明确的合同,我的算法违反了该合同。

Javadoc还读取:

抛出:

IllegalStateException-如果计算可检测到尝试对此地图进行递归更新,否则将永远无法完成

但是不会抛出该异常。 也没有任何ConcurrentModificationException。 相反,该程序永远不会停止。

解决此具体问题的最简单的使用现场解决方案是不使用ConcurrentHashMap,而仅使用HashMap:

static Map<Integer, Integer> cache = new HashMap<>();

覆盖超类型合约的子类型

Map.computeIfAbsent() HashMap.computeIfAbsent()Map.computeIfAbsent() Javadoc禁止这种递归计算,这当然是荒谬的,因为缓存的类型是Map<Integer, Integer> ,而不是ConcurrentHashMap<Integer, Integer> 。 子类型彻底重新定义超级类型协定是非常危险的( Set vs. SortedSet是问候)。 因此,在超级类型中也应禁止执行此类递归。

进一步参考

尽管合同问题只是人们的看法,但停顿问题显然是一个漏洞。 我还在Stack Overflow上记录了此问题,在该问题中 , Ben Manes提供了一个有趣的答案,导致了先前的错误报告(截至2015年初尚未解决):

  • https://bugs.openjdk.java.net/browse/JDK-8062841

我自己的报告(可能是上述报告的副本)也很快被接受,原因是:

  • https://bugs.openjdk.java.net/browse/JDK-8074374

Oracle正在研究此问题时,请记住:

切勿在ConcurrentHashMap.computeIfAbsent()方法内部进行递归。 如果您正在实现集合,并且认为编写一个可能无限的循环是个好主意,请再考虑一下,然后阅读我们的文章:

无限循环。 或者:可能出错的任何东西都可以 )

墨菲总是对的。

翻译自: https://www.javacodegeeks.com/2015/03/avoid-recursion-in-concurrenthashmap-computeifabsent.html

避免在ConcurrentHashMap.computeIfAbsent()中进行递归相关推荐

  1. java 建树源码_Java实现的二叉树常用操作【前序建树,前中后递归非递归遍历及层序遍历】...

    import java.util.ArrayDeque; import java.util.Queue; import java.util.Stack; //二叉树的建树,前中后 递归非递归遍历 层序 ...

  2. Sql中的递归问题-思考与建议

    Sql中的递归问题 [递归] 是一种循环方式或规则 树的遍历常常用到 优点:编写程序方便 缺点:限制与内存,容易崩溃 [描述] 类别表 CID,CName,FID FID=0表示此节点为根节点 如何在 ...

  3. 可能存在无限递归_做事永远无头无尾?人生中的递归现象

    不知道大家有没有发现,在自己身边的人或者说就是自己,无论在职场还是学习中,有时候会陷入一种瞎忙碌的状态, 在周围的人看来你很忙碌,但是一旦需要拿出成果的时候,却又显得不尽人意,而最近的我就陷入了这样一 ...

  4. vue树形结构html,怎么在vue中利用递归组件实现一个树形控件

    怎么在vue中利用递归组件实现一个树形控件 发布时间:2021-06-11 17:26:48 来源:亿速云 阅读:81 作者:Leah 本篇文章为大家展示了怎么在vue中利用递归组件实现一个树形控件, ...

  5. 递归函数python有什么特点_Python中的递归

    在前面的讲解中,函数的调用通常发生在彼此不同的函数之间.其实,函数还有一种特殊的调用方式,那就是自己调用自己,这种方式称为函数递归调用. 递归,在程序设计中也是一个常用的技巧,甚至是一种思维方式,非常 ...

  6. 递归javascript_使用freeCodeCamp挑战解释了JavaScript中的递归

    递归javascript In this article I will touch on a few important ideas to help you understand Recursion ...

  7. 递归javascript_JavaScript中的递归

    递归javascript by Kevin Ennis 凯文·恩尼斯(Kevin Ennis) JavaScript中的递归 (Recursion in JavaScript) I'm just go ...

  8. 计算机科学中的递归算法是把问题,从计算思维的视角辨析算法中的递归与迭代...

    周世杰 算法思维是计算思维的一个方面,而在计算机科学中,基于递归和迭代的思维方式在算法和程序设计中广泛应用,是算法思维的重要构成部分.因此,信息技术学科教师在基础课教学中辨析递归与迭代算法,将其作为发 ...

  9. C#中的递归APS和CPS模式详解(转载)

    这篇文章主要介绍了C#中的递归APS和CPS模式详解,本文讲解了累加器传递模式.CPS函数.CPS变换.CPS尾递归.尾递归与Continuation等内容,需要的朋友可以参考下 累加器传递模式(Ac ...

最新文章

  1. Android MVC结构的浅见【转】
  2. 图像及其表达与性质(上)
  3. Fencing the Cows [USACO]
  4. 大数据与web开发整合的最佳实践-思考
  5. RHEL5U8配置Centos yum源
  6. 摄像头YUV2格式详解
  7. 微信小程序“信用卡还款”项目实践
  8. 电子游戏销售数据分析
  9. 基于ANT+通讯协议软件开发环境搭建
  10. 【JZOJ】【卡特兰数】【高精】WZK打雪仗
  11. 【Debug】UserWarning: size_average and reduce args will be deprecated, please use reduction=‘sum‘
  12. 用python实现淘宝毫秒级秒!! 天猫淘宝的抢购完美实现 而且说实话有很多人需要它。 每次在抢购前的无法提交订单导致很多买家无法购买。 今天我教给大家如何更好快速实现你的购买愿望! 教程如下!请仔
  13. 如何利用免费工具轻松实现个人号裂变?
  14. 我的Python分析成长之路9
  15. 在windows 10中新建文本文档,只有txt文件双击打不开,但右键点编辑可以打开。
  16. 【扬汤止沸,不如釜底抽薪】夜来风雨声,Lucene知多少?
  17. $.ajax() 参数详解
  18. Php Adodb 初探
  19. win7安装onenote2016时碰到30094-1011(0)的 问题
  20. 数字化推动后市场产业变革,开启汽车后市场新篇章

热门文章

  1. linux container 原理,容器概念与Linux Container原理
  2. keyshot卡住了还能保存吗_相机希望你知道的13件事 keyshot相机切换事件
  3. java快排原理_Java数据结构与算法——快速排序
  4. python线性加权模型_局部加权之线性回归(1) - Python实现
  5. python 虚拟环境_理解Python虚拟环境
  6. oidc auth2.0_将Auth0 OIDC(OAUTH 2)与授权(组和角色)集成
  7. jvm回收垃圾_没有垃圾回收的JVM
  8. java12关键字var_Java 10:“ var”关键字
  9. 冷热复位_冷热rx-java可观察
  10. 处理Java异常的10种最佳实践