| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 系统运维 -> Java并发工具学习(六)——简单聊聊ConcurrentHashMap -> 正文阅读 |
|
[系统运维]Java并发工具学习(六)——简单聊聊ConcurrentHashMap |
文章目录前言上一篇简单絮叨了一下CAS和final关键字,这篇博客开始絮叨一下Java并发容器。HashMap,ArrayList这种都是非线程安全的。在Java中我们如果想将HashMap和ArrayList直接变成线程安全的,则可以通过如下方法来实现
但是这种代码底层其实用的是synchronized同步代码块,效率会大打折扣。在比较老的Java版本中,有Hashtable和Vector两个容器是线程安全的,如果从源码中查看,这两个集合中的关键方法都是synchronized修饰的,并发性能也不是很高。因此才有了专门的并发容器,这篇博客开始总结一下Java中的并发容器。 Map接口Map是key,value数据结构的顶层接口,我们常用的HashMap是Map接口的一个实现类。除了HashMap这个实现类,还有其他几个具体的实现类,每个都有不同的作用
HashMap的问题HashMap除了不是线程安全的,同时在多线程扩容的时候,还会出现死循环,这个内容有些恶心的面试官会问这种无聊且没有实际作用的问题。这里还是记录一下吧,不展开总结了,直接给出这个问题总结的比较好的文章——JAVA HASHMAP的死循环。 这种问题的根本在于将本身不支持并发的HashMap,强行用于并发的场景,而导致了出现链表循环指向的问题。如果面试遇到这种问题,可以内心鄙视一下面试官,因为这个问题真的有点无聊,就好比本来可以用圆的轮胎来造自行车,而某些人偏要用正方形的轮胎,完了还要问你为啥方形的轮胎造出来的自行车不实用。 总之一点——HashMap不能强行用于并发的场合。同时HashMap和ConcurrentHashMap在1.7和1.8的JDK版本中有较大的差异,这篇博客都会简单总结一下 1.7版本中的HashMap和ConcurrentHashMap1.7中的HashMap这个是比较简单的,标示Key的,就是一个数组,然后数组中的每个元素都是一个单向链表,如果存在hash冲突的时候,就会采用拉链法来存储冲突元素。 1.7中的ConcurrentHashMap1.7中的ConcurrentHashMap和HashMap差不多,但是ConcurrentHashMap是支持并发操作的。因此会稍微复杂点。由于ConcurrentHashMap支持分段锁,因此引入了一个槽(Segment)的数组。1.7中一个ConcurrentHashMap就是一个Segment的数组,Segment继承了ReentrantLock,因此线程每次在针对1.7中的ConcurrentHashMap进行并发操作的时候,只是锁住单个的Segment元素,只需要保证每个的Segment是线程安全的,就保证了整体的ConcurrentHashMap是线程安全的。 1.8版本中的HashMap和ConcurrentHashMap1.8中的HashMap结构
关于红黑树——红黑树详解。(个人认为,红黑树算法可移植性不强,只需简单了解即可) 1.8中的ConcurrentHashMap1.8中对1.7的ConcurrentHashMap做了大的改动,ConcurrentHashMap的结构如下 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-adjPh7g2-1637484353960)(F:\blog_doc\blogPic\sync&JUC-learn\4.png)] 和1.8中的HashMap似乎没有区别,不过要保证线程安全,因此在源码上要复杂很多。 相关源码 putVal
get
1.7和1.8中的对比针对1.7和1.8中的HashMap和ConcurrentHashMap只是做了一个简单的对比,没有做更进一步的介绍,至于扩容,迁移数据,这些参考文末最后的总结文档吧(个人觉得实在没必要了解到那个层级)。 在数据结构方面,1.8中针对hash冲突的数据,在达到一定阈值之后,引入了红黑树的结构进行存储,在ConcurrentHashMap中节点数组其实是可以扩容的 在保证并发方面,1.7采用的是分段锁,其中的Segment继承至ReentrantLock,而在1.8中保证线程安全的操作是通过CAS+synchronized来实现的。 在查询的时间复杂度,1.7中为O(n),1.8中为O(logN) 为什么1.8中要针对超过8个的冲突链表转换成红黑树呢?难道转换操作不更耗费性能么?这个在源码的注解中也有提及 一个简单实例
上述代码在多线程环境下运行,依旧不是线程安全的,因为其线程中虽然用到了ConcurrentHashMap,但是其修改值的操作并不是一个原子的操作,因此依旧不是线程安全的,这种错误在实际开发中是很常见的。正常的操作应该改成如下代码
总结推荐一下大牛对HashMap和ConcurrentHashMap的总结,本篇大部分内容都参考了这篇博客,甚至有些图片,就来自于这篇文章,个人觉得网上没有比这篇博客写的更好的总结了——Java7/8 中的 HashMap 和 ConcurrentHashMap 全解析。 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/16 0:32:23- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |