千家信息网

HashMap在多线程环境下的问题怎么避免

发表于:2024-12-03 作者:千家信息网编辑
千家信息网最后更新 2024年12月03日,这篇文章主要介绍"HashMap在多线程环境下的问题怎么避免",在日常操作中,相信很多人在HashMap在多线程环境下的问题怎么避免问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对
千家信息网最后更新 2024年12月03日HashMap在多线程环境下的问题怎么避免

这篇文章主要介绍"HashMap在多线程环境下的问题怎么避免",在日常操作中,相信很多人在HashMap在多线程环境下的问题怎么避免问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"HashMap在多线程环境下的问题怎么避免"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

在分析HashMap的并发问题前,先简单了解HashMap的put和get基本操作是如何实现的。

1.HashMap的put和get操作

大家知道HashMap内部实现是通过拉链法解决哈希冲突的,也就是通过链表的结构保存散列到同一数组位置的两个值,

put操作主要是判空,对key的hashcode执行一次HashMap自己的哈希函数,得到bucketindex位置,还有对重复key的覆盖操作。

对照源码分析一下具体的put操作是如何完成的:

涉及到的几个方法:


static int hash(int h) { h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4);}static int indexFor(int h, int length) { return h & (length-1);}

数据put完成以后,就是如何get,我们看一下get函数中的操作:

看一下链表的结点数据结构,保存了四个字段,包括key,value,key对应的hash值以及链表的下一个节点:


static class Entry implements Map.Entry { final K key;//Key-value结构的key V value;//存储值 Entry next;//指向下一个链表节点 final int hash;//哈希值 }

2.Rehash/再散列扩展内部数组长度

哈希表结构是结合了数组和链表的优点,在最好情况下,查找和插入都维持了一个较小的时间复杂度O(1),

不过结合HashMap的实现,考虑下面的情况,如果内部Entry[] tablet的容量很小,或者直接极端化为table长度为1的场景,那么全部的数据元素都会产生碰撞,

这时候的哈希表成为一条单链表,查找和添加的时间复杂度变为O(N),失去了哈希表的意义。

所以哈希表的操作中,内部数组的大小非常重要,必须保持一个平衡的数字,使得哈希碰撞不会太频繁,同时占用空间不会过大。

这就需要在哈希表使用的过程中不断的对table容量进行调整,看一下put操作中的addEntry()方法:


void addEntry(int hash, K key, V value, int bucketIndex) { Entry e = table[bucketIndex]; table[bucketIndex] = new Entry(hash, key, value, e); if (size++ >= threshold) resize(2 * table.length); }

这里面resize的过程,就是再散列调整table大小的过程,默认是当前table容量的两倍。


void resize(int newCapacity) { Entry[] oldTable = table; int oldCapacity = oldTable.length; if (oldCapacity == MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return; } Entry[] newTable = new Entry[newCapacity]; //初始化一个大小为oldTable容量两倍的新数组newTable transfer(newTable); table = newTable; threshold = (int)(newCapacity * loadFactor);}

关键的一步操作是transfer(newTable),这个操作会把当前Entry[] table数组的全部元素转移到新的table中,

这个transfer的过程在并发环境下会发生错误,导致数组链表中的链表形成循环链表,在后面的get操作时e = e.next操作无限循环,Infinite Loop出现。

下面具体分析HashMap的并发问题的表现以及如何出现的。

3.HashMap在多线程put后可能导致get无限循环

HashMap在并发环境下多线程put后可能导致get死循环,具体表现为CPU使用率100%,

看一下transfer的过程:

这里引用酷壳陈皓的博文:


并发下的Rehash

1)假设我们有两个线程。我用红色和浅蓝色标注了一下。

我们再回头看一下我们的 transfer代码中的这个细节:

而我们的线程二执行完成了。于是我们有下面的这个样子。

注意,因为Thread1的 e 指向了key(3),而next指向了key(7),其在线程二rehash后,指向了线程二重组后的链表。我们可以看到链表的顺序被反转后。

2)线程一被调度回来执行。

  • 先是执行 newTalbe[i] = e;

  • 然后是e = next,导致了e指向了key(7),

  • 而下一次循环的next = e.next导致了next指向了key(3)

3)一切安好。

线程一接着工作。把key(7)摘下来,放到newTable[i]的第一个,然后把e和next往下移。

4)环形链接出现。

e.next = newTable[i] 导致 key(3).next 指向了 key(7)

注意:此时的key(7).next 已经指向了key(3), 环形链表就这样出现了。

于是,当我们的线程一调用到,HashTable.get(11)时,悲剧就出现了--Infinite Loop。


针对上面的分析模拟这个例子,

这里在run中执行了一个自增操作,i++非原子操作,使用AtomicInteger避免可能出现的问题:


public static void main(String[] args){ MapThread t0 = new MapThread(); MapThread t1 = new MapThread(); // 省略 t2-t9 t0.start(); t1.start(); // 省略 t2-t9}

注意并发问题并不是一定会产生,可以多执行几次,

我试验了上面的代码很容易产生无限循环,控制台不能终止,有线程始终在执行中,

这是其中一个死循环的控制台截图,可以看到六个线程顺利完成了put工作后销毁,还有四个线程没有输出,卡在了put阶段,感兴趣的可以断点进去看一下:

上面的代码,如果把注释打开,换用ConcurrentHashMap就不会出现类似的问题。

4.多线程put的时候可能导致元素丢失

HashMap另外一个并发可能出现的问题是,可能产生元素丢失的现象。

考虑在多线程下put操作时,执行addEntry(hash, key, value, i),如果有产生哈希碰撞,

导致两个线程得到同样的bucketIndex去存储,就可能会出现覆盖丢失的情况:

5.使用线程安全的哈希表容器

那么如何使用线程安全的哈希表结构呢,这里列出了几条建议:

使用Hashtable 类,Hashtable 是线程安全的;

使用并发包下的java.util.concurrent.ConcurrentHashMap,ConcurrentHashMap实现了更高级的线程安全;

或者使用synchronizedMap() 同步方法包装 HashMap object,得到线程安全的Map,并在此Map上进行操作

到此,关于"HashMap在多线程环境下的问题怎么避免"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

线程 哈希 问题 指向 数组 环境 面的 循环 安全 结构 过程 元素 容量 方法 分析 学习 两个 代码 大小 情况 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 通过堡垒机连接数据库ora 软件开发排版方式有哪几种 易语言打码服务器端例 数据库文件加载到数据库中 盘点 网络安全法 济南市网络安全进校园知识竞赛 北大核心数据库 微信等社交媒体网络安全警示教育 性能最好的嵌入式kv数据库 嵌入式工业软件开发 cad软件开发的库 数据库系统怎样减少数据冗余 深职院计算机网络技术考证 网络安全论文范文1000字 东营市国家网络安全宣传 web服务器方式选择有哪些 修改网页需要在服务器上吗 对话网络安全专家图片 erp应用服务器 上海新时代网络技术哪家好 搞软件开发的英文叫什么软件 估算软件开发成本的技术 山东互联网软件开发费用是多少 海南潮流软件开发服务参考价格 怎么更换秘钥管理服务器地址 镇政府网络安全防范措施 软件开发模式常用术语 新基宏互联网科技有限公司 csgo啥是官方服务器 网络技术研究是干嘛的
0