为什么HashMap不是线程安全的
电面突然被问到这个问题,之前看到过,但是印象不深,导致自己没有答出来,现在总结一下。
HashMap的内部存储结构
transient Node<K,V>[] table;
static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;
}
使用了一个Node数组,这个Node数组的默认大小为16,所有hash值相同的key会存储到同一个链表中,HashMap的构成大概是这个样子(数组、链表、红黑树)
  
知道了hashmap的实现原理,那么再来谈一谈HashMap的自动扩容机制,默认的Node数组大小为16,如果有特别多的元素,比如说100万个元素,那么最优的情况下,每个hash桶有100万/16=62500个元素,那对于这么多元素来说,存取难度会增加,为了解决这个问题,加入了自动扩容机制。
说到自动扩容机制,首先要知道一些字段
int threshold; // 所能容纳的key-value对极限
final float loadFactor; // 负载因子
int modCount;
int size;
threshold是HashMap所能容纳的最大数据量的Node个数,loadFactor是负载因子,modCount用来记录HashMap内部结构发生变化的次数,size是记录实际存在的键值对数量。这里面,threshold=loadFactor*length,这个length是数组长度,当HashMap中元素超过threshold值的话,就发生自动扩容,例如初始的Node长度为16,负载因子为默认的0.75,那么如果元素个数超过了16*0.75=12的话,就会引发自动扩容,Node自动扩展为原来的两倍
那为什么HashMap线程不安全呢?
一、如果多个线程同时使用put方法,当key值一样时,可能会发生覆盖
二、如果多个线程同时检测到元素个数超过了loadFactor*数组大小,那么就会发生多个线程同时对Node数组进行扩容,都重新计算元素位置以及复制数据,但最终只有一个线程扩容后的数组会赋给table,那么其他线程的都会丢失,并且各自线程put的数据也会丢失。
HashMap在并发执行put操作的时候会引起死循环,导致CPU利用率接近100%,多线程会导致HashMap的Node链表行程环形数据结构,一旦行程环形数据结构,Node的next节点永远不为空,会在获取Node时产生死循环。
为什么HashMap不是线程安全的的更多相关文章
- 牛客网Java刷题知识点之为什么HashMap不支持线程的同步,不是线程安全的?如何实现HashMap的同步?
		
不多说,直接上干货! 这篇我是从整体出发去写的. 牛客网Java刷题知识点之Java 集合框架的构成.集合框架中的迭代器Iterator.集合框架中的集合接口Collection(List和Set). ...
 - 验证HashSet和HashMap不是线程安全
		
JAVA集合类: java.util包下的HashSet和HashMap类不是线程安全的, java.util.concurrent包下的ConcurrentHashMap类是线程安全的. 写2个测试 ...
 - 一次电话Java面试的问题总结(JDK8新特性、哈希冲突、HashMap原理、线程安全、Linux查询命令、Hadoop节点)
		
面试涉及问题含有: Java JDK8新特性 集合(哈希冲突.HashMap的原理.自动排序的集合TreeSet) 多线程安全问题 String和StringBuffer JVM 原理.运行流程.内部 ...
 - HashMap和Hashtable 线程安全性
		
HashMap和Hashtable的比较是Java面试中的常见问题,用来考验程序员是否能够正确使用集合类以及是否可以随机应变使用多种思路解决问题.HashMap的工作原理.ArrayList与Vect ...
 - HashMap为什么是线程不安全的
		
HashMap底层是一个Entry数组,当发生hash冲突的时候,hashmap是采用链表的方式来解决的,在对应的数组位置存放链表的头结点.对链表而言,新加入的节点会从头结点加入. 我们来分析一下多线 ...
 - (转载)两种方法让HashMap线程安全
		
HashMap不是线程安全的,往往在写程序时需要通过一些方法来回避.其实JDK原生的提供了2种方法让HashMap支持线程安全. 方法一:通过Collections.synchronizedMap() ...
 - HashMap非线程安全分析
		
通过各方资料了解,HashMap不是线程安全的,但是为什么不是线程安全的,在什么情况下会出现问题呢? 1. 下面对HashMap做一个实验,两个线程,并发写入不同的值,key和value相同,最后再看 ...
 - hashmap,hashTable concurrentHashMap 是否为线程安全,区别,如何实现的
		
线程安全类 在集合框架中,有些类是线程安全的,这些都是jdk1.1中的出现的.在jdk1.2之后,就出现许许多多非线程安全的类. 下面是这些线程安全的同步的类: vector:就比arraylist多 ...
 - HashMap线程不安全的体现
		
前言:我们都知道HashMap是线程不安全的,在多线程环境中不建议使用,但是其线程不安全主要体现在什么地方呢,本文将对该问题进行解密. 1.jdk1.7中的HashMap 在jdk1.8中对HashM ...
 
随机推荐
- MySql详解(五)
			
MySql详解(五) MySql库的管理 一.创建库 create database [if not exists] 库名[ character set 字符集名]; 二.修改库 alter data ...
 - [CQOI2009]叶子的染色
			
传送门:https://www.luogu.org/problemnew/show/P3155 一道挺水的树形dp题,然后我因为一个挺智障的问题debug了一晚上…… 嗯……首先想,如果一个点的颜色和 ...
 - JavaScript定时器的工作原理(翻译)
			
JavaScript定时器的工作原理(翻译) 标签(空格分隔): JavaScript定时器 最近在看ajax原理的时候,看到了一篇国外的文章,讲解了JavaScript定时器的工作原理,帮助我很好的 ...
 - 经实测解决Access-Control-Allow-Origin多域名跨域问题
			
网上流传2种方法解决多域名跨域问题:1.Access-Control-Allow-Origin:[域名一],[域名二]: 2.用$_SERVER("HTTP_ORIGIN")获取来 ...
 - java字符串利用dom4j转 xml 且遍历
			
1.因为转换的格式不是标准格式,所以有时候获得xml根目录后rootElement.attributes() 取不到想要的属性 所以需要通过迭代器来获取想要的值 public static void ...
 - Android 使用正则表达式验证身份证号是否符合规则
			
我国当前的身份证号分为三种: 一.15位身份证号 二.18位身份证号(前17位位数字,最后一位为字母x) 三.18为身份证号(18位都是数字) 具体验证请参考下面代码: /** * 验证身份证号是否符 ...
 - git reset之后找回本地未提交的代码
			
头脑发热使用了git reset命令回退到了之前的一个版本,结果把本地没有提交的代码给覆盖掉了..... 作为一个bug员自然是想恢复,毕竟重新写还得再测一遍,本着能懒一点是一点的原则,开始了恢复代码 ...
 - 20155327 EXP8 Web基础
			
20155320 EXP8 Web基础 基础问题回答 什么是表单? 表单:可以收集用户的信息和反馈意见,是网站管理者与浏览者之间沟通的桥梁. 表单由文本域.复选框.单选框.菜单.文件地址域.按钮等表单 ...
 - linux gz 解压缩
			
Linux压缩保留源文件的方法:gzip –c filename > filename.gzLinux解压缩保留源文件的方法:gunzip –c filename.gz > filenam ...
 - 【LG4248】[AHOI2013]差异
			
[LG4248][AHOI2013]差异 题面 洛谷 题解 后缀数组版做法戳我 我们将原串\(reverse\),根据后缀自动机的性质,两个后缀的\(lcp\)一定是我们在反串后两个前缀的\(lca\ ...