Java HashMap问题
1:map集合简述:
2:HashMap集合的实现:
3:HashMap的成员变量
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
-> 数组默认初始容量:16
static final int MAXIMUM_CAPACITY = 1 << 30;
-> 数组最大容量2 ^ 30 次方
static final float DEFAULT_LOAD_FACTOR = 0.75f;
-> 默认负载因子的大小:0.75
static final int MIN_TREEIFY_CAPACITY = 64;
-> 树形最小容量:哈希表的最小树形化容量,超过此值允许表中桶转化成红黑树
static final int TREEIFY_THRESHOLD = 8;
-> 树形阈值:当链表长度达到8时,将链表转化为红黑树
static final int UNTREEIFY_THRESHOLD = 6;
-> 树形阈值:当链表长度小于6时,将红黑树转化为链表
transient int modCount; -> hashmap修改次数
int threshold; -> 可存储key-value 键值对的临界值 需要扩充时;值 = 容量 * 加载因子
transient int size; 已存储key-value 键值对数量
final float loadFactor; -> 负载因子
transient Set< Map.Entry< K,V >> entrySet; -> 缓存的键值对集合
transient Node< K,V>[] table; -> 链表数组(用于存储hashmap的数据)
4:重写hashCode&&equals方法
如果没有重写 hashcode 方法,JDK 默认使用 Object 类 native 的 hashCode 方法,返回的是一般是一个与存储地址相关联的数
HashMap不能存储key值相同的数据,是因为在存储时,会先判断hashCode是否相同,紧接着equals继续判断
所以用到hashCode时,必然要重写hashCode和equals方法
例:写一个Student类,重写hashCode和equals方法
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return this.name+"--"+this.age;
}
@Override
public boolean equals(Object o) {
Student student=(Student) o;
return this.name.equals(student.name)&&this.age==student.age;
}
@Override
public int hashCode() {
return name.hashCode()+age*38;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
5:resize机制
HashMap的扩容机制就是重新申请一个容量是当前的2倍的桶数组,然后将原先的记录逐个重新映射到新的桶里面,然后将原先的桶逐个置为null使得引用失效。
扩容处理会遍历所有的元素,时间复杂度很高;经过一次扩容处理后,元素会更加均匀的分布在各个桶中,会提升访问效率。所以我们尽量避免进行扩容处理,当我们知道需要存储数据的个数时,在newHashMap时就给定初始容量,避免重复扩容
给定扩容容量我们必须要给定容量大于我们预计数据量的 1.34 倍,并且为2的幂次方
例如:如果是2个数据的话,将初始化容量设置为4。
如果预计大概会插入 12 条数据的话,那么初始容量为16简直是完美,一点不浪费,而且也不会扩容。
6:为什么HashMap线程不安全
1>put的时候导致的多线程数据不一致。
这个问题比较好想象,比如有两个线程A和B,首先A希望插入一个key-value对到HashMap中,首先计算记录所要落到的桶的索引坐标,然后获取到该桶里面的链表头结点,此时线程A的时间片用完了,而此时线程B被调度得以执行,和线程A一样执行,只不过线程B成功将记录插到了桶里面,假设线程A插入的记录计算出来的桶索引和线程B要插入的记录计算出来的桶索引是一样的,那么当线程B成功插入之后,线程A再次被调度运行时,它依然持有过期的链表头但是它对此一无所知,以至于它认为它应该这样做,如此一来就覆盖了线程B插入的记录,这样线程B插入的记录就凭空消失了,造成了数据不一致的行为。
2>发生在扩容时,重新调整HashMap大小的时候,多个线程确实存在条件竞争,因为如果两个线程都发现HashMap需要重新调整大小了,它们会同时试着调整大小。在调整大小的过程中,存储在LinkedList中的元素的次序会反过来,因为移动到新的bucket位置的时候,HashMap并不会将元素放在LinkedList的尾部,而是放在头部,这是为了避免尾部遍历(tail traversing)。如果条件竞争发生了,那么就死循环了。这个时候,你可以质问面试官,为什么这么奇怪,要在多线程的环境下使用HashMap呢?
Java HashMap问题的更多相关文章
- [翻译]Java HashMap工作原理
大部分Java开发者都在使用Map,特别是HashMap.HashMap是一种简单但强大的方式去存储和获取数据.但有多少开发者知道HashMap内部如何工作呢?几天前,我阅读了java.util.Ha ...
- Java学习笔记(二二)——Java HashMap
[前面的话] 早上起来好瞌睡哈,最近要注意一样作息状态. HashMap好好学习一下. [定义] Hashmap:是一个散列表,它存储的内容是键值对(key——value)映射.允许nul ...
- java集合框架之java HashMap代码解析
java集合框架之java HashMap代码解析 文章Java集合框架综述后,具体集合类的代码,首先以既熟悉又陌生的HashMap开始. 源自http://www.codeceo.com/arti ...
- HashMap的原理与实 无锁队列的实现Java HashMap的死循环 red black tree
http://www.cnblogs.com/fornever/archive/2011/12/02/2270692.html https://zh.wikipedia.org/wiki/%E7%BA ...
- 【转】Java HashMap工作原理(好文章)
大部分Java开发者都在使用Map,特别是HashMap.HashMap是一种简单但强大的方式去存储和获取数据.但有多少开发者知道HashMap内部如何工作呢?几天前,我阅读了java.util.Ha ...
- 【转】Java HashMap 源码解析(好文章)
.fluid-width-video-wrapper { width: 100%; position: relative; padding: 0; } .fluid-width-video-wra ...
- 转:Java HashMap实现详解
Java HashMap实现详解 转:http://beyond99.blog.51cto.com/1469451/429789 1. HashMap概述: HashMap是基于哈希表的M ...
- 自学Java HashMap源码
自学Java HashMap源码 参考:http://zhangshixi.iteye.com/blog/672697 HashMap概述 HashMap是基于哈希表的Map接口的非同步实现.此实现提 ...
- Java HashMap工作原理及实现
Java HashMap工作原理及实现 2016/03/20 | 分类: 基础技术 | 0 条评论 | 标签: HASHMAP 分享到:3 原文出处: Yikun 1. 概述 从本文你可以学习到: 什 ...
- 【转】Java HashMap的死循环
问题的症状 从前我们的Java代码因为一些原因使用了HashMap这个东西,但是当时的程序是单线程的,一切都没有问题.后来,我们的程序性能有问题,所以需要变成多线程的,于是,变成多线程后到了线上,发现 ...
随机推荐
- Spring、SpringMVC、SpringBoot、SpringCloud概述
spring和springMvc: 1. spring是一个一站式的轻量级的java开发框架,核心是控制反转(IOC)和面向切面(AOP),针对于开发的WEB层(springMvc).业务层(Ioc) ...
- Docker 镜像添加模块
Docker 镜像添加模块 1. 使用root用户进入一个新容器,不要用 --rm .否则退出容器的时候,容器没有了 docker run --user 0 -it --name superman ...
- U200-SNMP
U200配置snmp snmp-agent sys-info version v2c snmp-agent community read jkzh snmp-agent trap enable snm ...
- 手机app安装包apk/ipa放到网上无法下载原因及教程
做好APP后,APP名为app.apk或app.ipa 上传到根目录后,生成二维码 但还是无法下载,哪按以下教程让服务器apache/iis/nginx支持.apk/ipa文件下载 windows i ...
- zabbix历史数据全部清楚
#这种方法会出现 监控项不可用的情况 1.停掉zabbix_server 2.重重名表 RENAME TABLE history to history_20180117; RENAME TABLE h ...
- (转)Android OpenGL ES(一)
转:http://wiki.jikexueyuan.com/project/opengl-es-guide/pipeline.html OpenGL ES 主要用来开发 3D 图形应用的.OpenGL ...
- python reduce()函数使用
reduce()的使用方法形如reduce(function, iterable[, initializer]),它的形式和map()函数一样.不过参数f(x)必须有两个参数,initializer是 ...
- postgresql的规则系统
" class="wiz-editor-body wiz-readonly" contenteditable="false"> Postgres ...
- MySQL-8.0填坑
Client does not support authentication protocol 或 Authentication plugin 'caching_sha2_password' cann ...
- 88、展示Tensorflow计算图上每个节点的基本信息以及运行时消耗的时间和空间
''' Created on May 24, 2017 @author: p0079482 ''' #使用程序输出日志 import tensorflow as tf with tf.Session( ...