避免在ConcurrentHashMap.computeIfAbsent()中进行递归
有时我们会提供糟糕的建议。 就像该文章中有关如何将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()中进行递归相关推荐
- java 建树源码_Java实现的二叉树常用操作【前序建树,前中后递归非递归遍历及层序遍历】...
import java.util.ArrayDeque; import java.util.Queue; import java.util.Stack; //二叉树的建树,前中后 递归非递归遍历 层序 ...
- Sql中的递归问题-思考与建议
Sql中的递归问题 [递归] 是一种循环方式或规则 树的遍历常常用到 优点:编写程序方便 缺点:限制与内存,容易崩溃 [描述] 类别表 CID,CName,FID FID=0表示此节点为根节点 如何在 ...
- 可能存在无限递归_做事永远无头无尾?人生中的递归现象
不知道大家有没有发现,在自己身边的人或者说就是自己,无论在职场还是学习中,有时候会陷入一种瞎忙碌的状态, 在周围的人看来你很忙碌,但是一旦需要拿出成果的时候,却又显得不尽人意,而最近的我就陷入了这样一 ...
- vue树形结构html,怎么在vue中利用递归组件实现一个树形控件
怎么在vue中利用递归组件实现一个树形控件 发布时间:2021-06-11 17:26:48 来源:亿速云 阅读:81 作者:Leah 本篇文章为大家展示了怎么在vue中利用递归组件实现一个树形控件, ...
- 递归函数python有什么特点_Python中的递归
在前面的讲解中,函数的调用通常发生在彼此不同的函数之间.其实,函数还有一种特殊的调用方式,那就是自己调用自己,这种方式称为函数递归调用. 递归,在程序设计中也是一个常用的技巧,甚至是一种思维方式,非常 ...
- 递归javascript_使用freeCodeCamp挑战解释了JavaScript中的递归
递归javascript In this article I will touch on a few important ideas to help you understand Recursion ...
- 递归javascript_JavaScript中的递归
递归javascript by Kevin Ennis 凯文·恩尼斯(Kevin Ennis) JavaScript中的递归 (Recursion in JavaScript) I'm just go ...
- 计算机科学中的递归算法是把问题,从计算思维的视角辨析算法中的递归与迭代...
周世杰 算法思维是计算思维的一个方面,而在计算机科学中,基于递归和迭代的思维方式在算法和程序设计中广泛应用,是算法思维的重要构成部分.因此,信息技术学科教师在基础课教学中辨析递归与迭代算法,将其作为发 ...
- C#中的递归APS和CPS模式详解(转载)
这篇文章主要介绍了C#中的递归APS和CPS模式详解,本文讲解了累加器传递模式.CPS函数.CPS变换.CPS尾递归.尾递归与Continuation等内容,需要的朋友可以参考下 累加器传递模式(Ac ...
最新文章
- Android MVC结构的浅见【转】
- 图像及其表达与性质(上)
- Fencing the Cows [USACO]
- 大数据与web开发整合的最佳实践-思考
- RHEL5U8配置Centos yum源
- 摄像头YUV2格式详解
- 微信小程序“信用卡还款”项目实践
- 电子游戏销售数据分析
- 基于ANT+通讯协议软件开发环境搭建
- 【JZOJ】【卡特兰数】【高精】WZK打雪仗
- 【Debug】UserWarning: size_average and reduce args will be deprecated, please use reduction=‘sum‘
- 用python实现淘宝毫秒级秒!! 天猫淘宝的抢购完美实现 而且说实话有很多人需要它。 每次在抢购前的无法提交订单导致很多买家无法购买。 今天我教给大家如何更好快速实现你的购买愿望! 教程如下!请仔
- 如何利用免费工具轻松实现个人号裂变?
- 我的Python分析成长之路9
- 在windows 10中新建文本文档,只有txt文件双击打不开,但右键点编辑可以打开。
- 【扬汤止沸,不如釜底抽薪】夜来风雨声,Lucene知多少?
- $.ajax() 参数详解
- Php Adodb 初探
- win7安装onenote2016时碰到30094-1011(0)的 问题
- 数字化推动后市场产业变革,开启汽车后市场新篇章
热门文章
- linux container 原理,容器概念与Linux Container原理
- keyshot卡住了还能保存吗_相机希望你知道的13件事 keyshot相机切换事件
- java快排原理_Java数据结构与算法——快速排序
- python线性加权模型_局部加权之线性回归(1) - Python实现
- python 虚拟环境_理解Python虚拟环境
- oidc auth2.0_将Auth0 OIDC(OAUTH 2)与授权(组和角色)集成
- jvm回收垃圾_没有垃圾回收的JVM
- java12关键字var_Java 10:“ var”关键字
- 冷热复位_冷热rx-java可观察
- 处理Java异常的10种最佳实践