关于Java两点需要更新的知识
关于Java两点需要更新的知识
HashMap的初始容量
背景
很多人可以把HashMap的原理描述的很溜。比如JDK1.7之前,底层数据结构是数组+链表。JDK1.8之后,出于效率上的考虑,在数组长度大于64,链表长度大于8的时候,会转换为红黑树。
甚至知道对于赋值了容量的都会做一个变成2的n次方的操作。它的hash方法为了防止高位变化大或者低位变化大将它本身hash值右移16位和自身原hash值做一个按位异或操作再与容量-1做按位与。还知道默认的负载因子是0.75,这个值是经过概率论统计出来的,最好不要改。
了解的这么清楚,我就想问一下为什么从数据库中取出来一个list,之后转换成hashmap。直接用的是Map map = new HashMap()或者是Map map = Maps.newHashMap(),为什么不赋初始容量呢?
分析
容量的大小会在put过程中发生resize操作。如果初始不赋值。默认容量是16。那比如从数据库中取出来1000个元素。put过程中会从16->32->64->128……,运行多次resize操作。resize操作数组,需要将所有元素进行复制和rehash,效率是很低的。
所以也有一些同学考虑到这个问题,代码是这么写的: Map map = new HashMap(list.size());
这个写法也有问题,因为resize并不是到达容量上限才resize。为了尽量避免hash冲突,是超过阈值threshold就扩容。而这个threshold=容量*负载因子。
所以我更建议的写法是Map map = new HashMap(list.size()/负载因子)。
这样理论上可以比Map map = new HashMap(list.size())减少一次resize。
总结
在可以确定HashMap容量时,最好Map map = new HashMap(list.size()/负载因子)来初始化,避免自动扩容带来的性能损耗。
思考
ConcurrentHashMap怎么来更合理的初始化?
JVM内存结构和Java内存模型
背景
前段时间偶然看到有篇文章批判很多人对「JVM内存模型」这个概念不清楚,说这个经典的图并不是内存模型而是内存结构。
而内存模型应该是JSR133规范里介绍的volatile、final和synchronized等关键字的内存语义。
分析
这个非常富有淘金式思维的作者却搞混了一个概念,看看下面JSR-133规范里是怎么说的:JSR133规范里讲的Java内存模型,并没有说是JVM的内存模型啊。
Java内存模型讲的是Java语言本身的规范,这个规范包含了各个Java标准关键字在JVM里是怎样运作的。而JVM内存模型描述的是Java虚拟机怎样运行字节码的。所以上面经典的图说是JVM内存模型也不为过。不过根据官网,叫JVM内存结构更为标准。证据如下:
https://docs.oracle.com/javase/specs/jvms/se14/html/jvms-2.html#jvms-2.5
在oracle官网里,介绍了这个概念
总结
Java内存模型和JVM内存模型是两个概念。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
JavaScript设计模式学习笔记
《JavaScript设计模式与开发实践》14种设计模式学习笔记。 单例模式策略模式代理模式迭代器模式发布-订阅模式命令模式组合模式模板方法模式享元模式职责链模式中介者模式装饰者模式状态模式适配器模式单例模式保证一个类仅有一个实例,并提供一个全局访问点。 // 构造函数var Singleton = function (name) { this.name = name;}Singleton.prototype.getName = function () { alert(this.name);} // 方案1 绑定到构造函数上Singleton.instance = null;Singleton.getInstance = function (name) { if (!this.instance) { this.instance = new Singleton(name); } return this.instance;} // 方案2 闭包Singleton.getInstance = (function () { var instance = null; return functio...
- 下一篇
《机器学习Python实现_09_01_决策树_ID3与C4.5》
《机器学习Python实现_09_01_决策树_ID3与C4.5》 简介先看一个例子,某银行是否给用户放贷的判断规则集如下: if 年龄==青年: if 有工作==是: if 信贷情况==非常好: 放 else: 不放 else: if 有自己的房子==是: if 信贷情况==一般: 不放 else: 放 else: if 信贷情况==非常好 or 信贷情况==好: 放 else: if 有工作==是: 放 else: 不放 elif 年龄==中年: if 有自己的房子==是: 放 else: if 信贷情况==非常好 or 信贷情况==好: 放 else: if 有工作==是: 放 else: 不放 elif 年龄==老年: if 有自己的房子==是: if 信贷情况==非常好 or 信贷情况==好: 放 else: 不放 else: if 信贷情况==非常好 or 信贷情况==好: if 有工作==是: 放 else: 不放 else: 不放 if 有自己的房子==是: 放 else: if 有工作==是: 放 else: 不放 眼力好的同学立马会发现这代码写的有问题,比如只要信贷...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
-
Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8编译安装MySQL8.0.19
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
推荐阅读
最新文章
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS6,CentOS7官方镜像安装Oracle11G
- SpringBoot2整合Redis,开启缓存,提高访问速度
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Hadoop3单机部署,实现最简伪集群