雇人做淘宝网站多少钱,科技公司网页图片,临时展厅搭建方案,重庆巨能建设集团网站有时我们会提供糟糕的建议。 就像该文章中有关如何将Java 8用于缓存的功能性方法来计算斐波那契数的文章一样 。 正如我们的读者之一马蒂亚斯#xff08;Matthias#xff09;在评论中注意到的那样 #xff0c;提出的算法可能永远不会停止。 考虑以下程序#xff1a; publi… 有时我们会提供糟糕的建议。 就像该文章中有关如何将Java 8用于缓存的功能性方法来计算斐波那契数的文章一样 。 正如我们的读者之一马蒂亚斯Matthias在评论中注意到的那样 提出的算法可能永远不会停止。 考虑以下程序 public class Test {static MapInteger, 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\Lukasjava -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 MapInteger, Integer cache new HashMap();覆盖超类型合约的子类型 Map.computeIfAbsent() HashMap.computeIfAbsent()或Map.computeIfAbsent() Javadoc禁止这种递归计算这当然是荒谬的因为缓存的类型是MapInteger, Integer 而不是ConcurrentHashMapInteger, 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