Java 8中的HashMap性能改进

HashMap<K, V>是每个Java程序中快速,通用且无处不在的数据结构。 首先是一些基础知识。 您可能知道,它使用键的hashCode()equals()方法在存储桶之间拆分值。 存储桶(箱)的数量应略高于映射中的条目数,以便每个存储桶仅保留很少(最好是一个)值。 当按键查找时,我们很快确定了存储桶(使用hashCode()模数number_of_buckets模),并且我们的商品在固定时间可用。

这应该已经为您所了解。 您可能还知道,哈希冲突对HashMap性能具有灾难性的影响。 当多个hashCode()值最终出现在同一存储桶中时,这些值将放置在临时链接列表中。 在最坏的情况下,当所有键都映射到同一存储桶时,会将哈希映射退化为链表–从O(1)到O(n)查找时间。 让我们首先对HashMap在Java 7(1.7.0_40)和Java 8(1.8.0-b132)中的正常情况下的行为进行基准测试。 为了完全控制hashCode()行为,我们定义了自定义Key类:

class Key implements Comparable<Key> {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 HashMap<Key, 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()确实是O(1):

1个

有趣的是,在简单的HashMap.get() Java 8平均比Java 7快20%。 整体性能同样令人感兴趣:即使在HashMap有100万个条目,一次查找所用的时间也不到10纳秒,这意味着我的机器上大约有20个CPU周期* 。 令人印象深刻! 但这不是我们要进行基准测试的结果。

假设我们有一个非常差的映射键,它总是返回相同的值。 这是最糟糕的情况,完全HashMap使用HashMap

class Key implements Comparable<Key> {//...@Overridepublic int hashCode() {return 0;}
}

我使用了完全相同的基准来查看它在各种地图尺寸下的行为(注意这是对数对数比例):

2

预计Java 7的结果。 HashMap.get()的成本与HashMap本身的大小成比例地增长。 由于所有条目都在一个巨大的链接列表中的同一存储桶中,因此查找一个条目平均需要遍历该列表的一半(大小为n)。 因此,O(n)复杂度如图所示。

但是Java 8的性能要好得多! 这是一个对数标度,因此我们实际上在谈论几个数量级的更好。 在灾难性哈希冲突的情况下,在JDK 8上执行的相同基准会产生O(logn)最坏情况的性能,如将JDK 8单独以对数线性比例可视化,则可以更好地看到:

3

即使使用big-O表示法,如此巨大的性能改进背后的原因是什么? 好,在JEP-180中描述了此优化。 基本上,当存储桶过大时(当前: TREEIFY_THRESHOLD = 8 ), HashMap用树形图的临时实现动态替换它。 这样一来,我们不必感到悲观的O(n),而获得更好的O(logn)。 它是如何工作的? 好吧,以前具有冲突键的条目只是简单地附加到链表中,而后又需要遍历。 现在, HashMap使用哈希码作为分支变量,将列表提升为二叉树。 如果两个散列不同,但最终在同一个存储桶中,则认为一个散列较大并向右移动。 如果哈希值相等(如本例所示),则HashMap希望键是Comparable ,以便它可以建立一些顺序。 这不是HashMap密钥的要求,但显然是一种好习惯。 如果密钥不具有可比性,那么在发生大量哈希冲突的情况下,不要指望任何性能提高。

为什么所有这些都那么重要? 知道我们使用的哈希算法的恶意软件可能会处理数千个请求,这些请求将导致大量的哈希冲突。 重复访问此类密钥将严重影响服务器性能,从而有效地导致拒绝服务攻击。 在JDK 8中,从O(n)到O(logn)的惊人跳跃将阻止这种攻击媒介,也使性能更具预测性。 我希望这将最终说服您的老板升级。


*在Intel Core i7-3635QM @ 2.4 GHz,8 GiB RAM和SSD驱动器上执行的基准,在64位Windows 8.1和默认JVM设置上运行。

翻译自: https://www.javacodegeeks.com/2014/04/hashmap-performance-improvements-in-java-8.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/363840.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

css 汉字注音,日本语片假名

代码 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">2 <html xmlns"http://www.w3.org/1999/xhtml">3 4 <head>5 <meta content"te…

Microsoft .NET 框架资源基础 ---摘自:msdn

Chris SellsSells Brothers Consulting 摘要&#xff1a;Chris Sells 讨论无类型清单资源和有类型资源&#xff0c;它们是受 Microsoft .NET 框架支持的两种资源。他定义了这两种资源&#xff0c;并介绍了如何在您自己的应用程序中使用它们。 下载 winforms02202003.exe 示例文…

Elasticsearch-kopf导览

当我需要一个插件来显示Elasticsearch的集群状态时&#xff0c;或者需要深入了解通常为经典插件elasticsearch-head所达到的索引时。 由于有很多建议&#xff0c;而且似乎是非官方的继任者&#xff0c;所以我最近对elasticsearch-kopf进行了更详细的介绍 。 我喜欢它。 我不确…

文字阴影-CSS Text-Shadow

1<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">2<html xmlns"http://www.w3.org/1999/xhtml">3<head>4<title>文字阴影-CSS Text-Shad…

javascript动态创建radio button元素支持IE/Firefox

我们都知道在IE中创建表单元素可以有三种方式varoInput document.createElement("input");varoInput document.createElement("<input />");varoInput document.createElement("<input name />");在Firefox里面仅支持varoInput docu…

如何在Android Studio中添加RecyclerView-v7支持包

首先右键你的项目然后选择 open module Settings 之后会出现这个界面&#xff0c;选择 Modules 下的app ,>>> Dependencies >>>点击右边的“” 选择第一项Library dependency 出现此界面&#xff0c;然后选择你所需要的 转载于:https://www.cnblogs.com/lcx9…

浮动层图片鼠标指针移到自动放大

html code:1<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">2<html xmlns"http://www.w3.org/1999/xhtml">3<head>4<title>缔友计算机信…

字符大小端aix linux,long, unsigned long不是跨平台的(慎用)

项目中用到long、long long等字段&#xff0c;遇到一些问题。先说得到的一些结论&#xff1a;大小端&#xff1a;Windows、Linux是小端&#xff0c;AIX是大端。sizeof(指针类型)程序位数/8。long、unsigned long不是跨平台的&#xff0c;一定要慎用。自己写了程序测试各平台下(…

Java构建工具:Ant vs. Maven vs Gradle

最初&#xff0c;Make是唯一可用的构建工具。 后来通过GNU Make进行了改进。 但是&#xff0c;从那时起&#xff0c;我们的需求增加了&#xff0c;结果&#xff0c;构建工具也不断发展。 JVM生态系统主要由三个构建工具组成&#xff1a; 常春藤的 Apache Ant 马文 摇篮 An…

Asp.Net中用javascript实现弹出窗口永远居中

//Asp.Net中用javascript实现弹出窗口永远居中functionShowDialog(url) { var iWidth600; //模态窗口宽度 var iHeight500;//模态窗口高度 var iTop(window.screen.height-iHeight)/2; var iLeft(window.screen.width-iWidth)/2; window.open(url,"Detail"…

Linux Vim 光标错位,技术|Vim 复制粘帖格式错乱问题的解决办法

有时候&#xff0c;复制文本(尤其是代码)到 Vim&#xff0c;会出现格式错乱的问题。看样子&#xff0c;应该是自动缩进惹得祸。本文不去深究原因&#xff0c;直接给出解决方法。1. paste 模式运行如下命令&#xff0c;进入 paste 模式&#xff1a;:set paste进入 paste 模式后&…

kali vmtools 不能复制粘贴解决方法(绝对实用)

朋友问起怎么vm kali 2019怎么不能复制了&#xff0c;而且网上的方法大多不适合。我就在这儿记录一笔吧&#xff0c;方便大家。 之前发现最新kali复制粘贴不能用&#xff0c;后来发现一个奇妙的套路&#xff0c;不是共享文件夹。只需要把文件复制到命令行中&#xff0c;会出现t…

MineCraft和堆外内存

总览 MineCraft是一个很好的例子&#xff0c;说明何时堆外内存确实可以提供帮助。 关键要求是&#xff1a; 保留的数据大部分是一个简单的数据结构&#xff08;在我的世界的情况下&#xff0c;它的很多字节[]&#xff09; 堆外内存的使用可以隐藏在抽象中。 考试 我使用以下测…

kubernetes进阶之七:Service

1.概述 Service也是Kubernetes里的最核心的资源对象之一&#xff0c;Kubernetes里的每个Service其实就是我们经常提起的微服务架构中的一个“微服务”&#xff0c;之前我们所说的Pod、RC等资源对象其实都是为这节所说的“服务”------Kubernetes Service作“嫁衣”的。图1.12显…

Json Schema的使用

直接上案例&#xff1a; 在Web Api通讯中&#xff0c;客户端发送json数据&#xff0c;服务端反序列化json&#xff08;json与某个类形成对应关系&#xff09;&#xff0c;在某些情况下&#xff0c;需要校验其上传的json是否合法。 服务端是使用Json.net(newtonsoft.json)进行…

红帽企业版linux 7.4更新启动,红帽Linux企业版7.4 淘汰Btrfs文件系统

我们不得不承认Btrfs是一种古老的文件系统&#xff0c;当初(2007年)是由甲骨文宣布并进行中的COW(copy-on-write式)文件系统&#xff0c;意图取代Linux的ext。但是天不遂人愿&#xff0c;2011年8月9日&#xff0c;Fedora就决定Btrfs不再作为Fedora 16默认文件系统&#xff0c;走…

关于控件postback 后viewstate加载失败的问题

我写了一个控件Inherits TextBox&#xff0c;里面有一个复杂属性Tip&#xff0c;但每次postback的时候都说加载viewstate失败&#xff0c;除非我在!postback的情况下给Tip.xxx赋值. 下面我贴出代码&#xff0c;我已经搞了一天了&#xff0c;搞不出什么原因。 JTextBox控件 usin…

天猫浏览型应用的CDN静态化架构演变(转)

在天猫双11活动中&#xff0c;商品详情、店铺等浏览型系统&#xff0c;通常会承受超出日常数倍甚至数十倍的流量冲击。随着历年来双11流量的大幅增加&#xff0c;每年这些浏览型 系统都要面临容量评估、硬件扩容、性能优化等各类技术挑战。因此&#xff0c;架构方面的重点在于&…

查看您的Solr缓存大小:Eclipse Memory Analyzer

Solr使用不同的缓存来防止请求期间过多的IO访问和计算。 当索引不是很频繁发生时&#xff0c;您可以通过使用这些缓存来获得巨大的性能提升。 根据索引数据的结构和缓存的大小&#xff0c;它们可能会变得很大&#xff0c;并占用堆内存的很大一部分。 在本文中&#xff0c;我想展…

会话跟踪之Session

Session是服务端使用记录客户端状态的一种机制&#xff0c;Session使用简单&#xff0c;但是和Cookie相比&#xff0c;增加了服务器的存储压力【因为为了追求速度&#xff0c;服务器将Session放置在了内存中】。Cookie是保存在客户端的&#xff0c;然而Session是保存在服务器上…