公信域名和网站建设是一样的吗,手表网站哪个最好知乎,wordpress文章段落背景颜色代码,平台公司是干什么的java8hashmapHashMapK, V是每个Java程序中快速#xff0c;通用且无处不在的数据结构。 首先是一些基础知识。 您可能知道#xff0c;它使用键的hashCode()和equals()方法在存储桶之间拆分值。 存储桶#xff08;箱#xff09;的数量应略高于映射中的条目数#xf… java8hashmap HashMapK, V是每个Java程序中快速通用且无处不在的数据结构。 首先是一些基础知识。 您可能知道它使用键的hashCode()和equals()方法在存储桶之间拆分值。 存储桶箱的数量应略高于映射中的条目数以使每个存储桶仅保留很少最好是一个值。 当按键查找时我们很快确定了存储桶使用hashCode()模数number_of_buckets模并且我们的商品在固定时间可用。 这应该已经为您所了解。 您可能还知道哈希冲突对HashMap性能具有灾难性的影响。 当多个hashCode()值最终出现在同一存储桶中时这些值将放置在临时链接列表中。 在最坏的情况下当所有键都映射到同一存储桶时会将哈希映射退化为链表–从O1到On查找时间。 让我们首先对HashMap在Java 71.7.0_40和Java 81.8.0-b132中的正常情况下的行为进行基准测试。 为了完全控制hashCode()行为我们定义了自定义Key类 class Key implements ComparableKey {private final int value;Key(int value) {this.value value;}Overridepublic int compareTo(Key o) {return Integer.compare(this.value, o.value);}Overridepublic boolean equals(Object o) {if (this o) return true;if (o null || getClass() ! o.getClass())return false;Key key (Key) o;return value key.value;}Overridepublic int hashCode() {return value;}
} Key类行为良好它覆盖equals()并提供了体面的hashCode() 。 为了避免过多的GC我缓存了不可变的Key实例而不是一遍又一遍地创建它们 public class Keys {public static final int MAX_KEY 10_000_000;private static final Key[] KEYS_CACHE new Key[MAX_KEY];static {for (int i 0; i MAX_KEY; i) {KEYS_CACHE[i] new Key(i);}}public static Key of(int value) {return KEYS_CACHE[value];}} 现在我们准备进行一些实验。 我们的基准测试将使用连续键空间简单地创建不同大小10的幂从1到1百万的HashMap 。 在基准测试本身中我们将根据键查找值并测量所需的时间具体取决于HashMap大小 import com.google.caliper.Param;
import com.google.caliper.Runner;
import com.google.caliper.SimpleBenchmark;public class MapBenchmark extends SimpleBenchmark {private HashMapKey, Integer map;Paramprivate int mapSize;Overrideprotected void setUp() throws Exception {map new HashMap(mapSize);for (int i 0; i mapSize; i) {map.put(Keys.of(i), i);}}public void timeMapGet(int reps) {for (int i 0; i reps; i) {map.get(Keys.of(i % mapSize));}}} 结果确认HashMap.get()确实是O1 有趣的是在简单的HashMap.get() Java 8平均比Java 7快20。 整体性能同样令人感兴趣即使在HashMap有100万个条目一次查找所用的时间也不到10纳秒这意味着我的机器上大约有20个CPU周期* 。 令人印象深刻 但这不是我们要进行基准测试的结果。 假设我们有一个非常差的映射键它总是返回相同的值。 这是最糟糕的情况完全HashMap使用HashMap class Key implements ComparableKey {//...Overridepublic int hashCode() {return 0;}
} 我使用了完全相同的基准来查看它在各种地图尺寸下的行为注意这是对数对数比例 预计Java 7的结果。 HashMap.get()的成本与HashMap本身的大小成比例地增长。 由于所有条目都在一个巨大的链接列表中的同一存储桶中因此查找一个条目平均需要遍历该列表的一半大小为n。 因此On复杂度如图所示。 但是Java 8的性能要好得多 这是一个对数刻度因此我们实际上在谈论几个数量级的更好。 在灾难性哈希冲突的情况下在JDK 8上执行的相同基准会产生Ologn最坏情况的性能如将JDK 8单独以对数线性比例显示时会更好地显示 即使使用big-O表示法如此巨大的性能改进背后的原因是什么 好在JEP-180中描述了此优化。 基本上当存储桶变得太大时当前 TREEIFY_THRESHOLD 8 HashMap用树形图的临时实现动态替换它。 这样我们不必感到悲观的On而会得到更好的Ologn。 它是如何工作的 好吧以前具有冲突键的条目只是简单地附加到链表中而后又需要遍历。 现在 HashMap使用哈希码作为分支变量将列表提升为二叉树。 如果两个散列不同但最终在同一个存储桶中则认为一个更大并向右移动。 如果哈希值相等如本例所示则HashMap希望键是Comparable 以便它可以建立一些顺序。 这不是HashMap密钥的要求但显然是一种好习惯。 如果密钥不具有可比性那么在发生大量哈希冲突的情况下不要指望任何性能提高。 为什么所有这些都那么重要 知道我们使用的哈希算法的恶意软件可能会处理数千个请求这些请求将导致大量的哈希冲突。 重复访问此类密钥将严重影响服务器性能从而有效地导致拒绝服务攻击。 在JDK 8中从On到Ologn的惊人跳变将阻止这种攻击向量也使性能更具预测性。 我希望这将最终说服您的老板升级。 *在Intel Core i7-3635QM 2.4 GHz8 GiB RAM和SSD驱动器上执行的基准在64位Windows 8.1和默认JVM设置上运行。 翻译自: https://www.javacodegeeks.com/2014/04/hashmap-performance-improvements-in-java-8.htmljava8hashmap