ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

HashMap、HashTable、ConcurrentHashMap详细区别

HashMap、HashTable、ConcurrentHashMap详细区别 目录1. 全方位对比表格1.1 线程安全与锁机制1.2 null‑value规则1.3 默认容量、扩容、底层数据结构2. 底层细节区分2.1 HashTable为什么现在不推荐使用?2.2 ConcurrentHashMap相较于HashTable优势3. 面试高频问答题库前言本篇文章专注剖析 HashMap、HashTable、ConcurrentHashMap 的底层差异、版本迭代细节、并发坑点以及面试考点适合用来复盘Java并发集合知识。1. 全方位对比表格1.1 线程安全与锁机制容器线程安全性上锁原理HashMap非线程安全没有添加任何锁多线程并发编程中写入会产生数据覆盖、环形链表等问题HashTable线程安全所有读和写的方法添加了synchronized锁住整张哈希表对象全局独占锁并发的性能较差ConcurrentHashMap线程安全采用桶头结点锁CAS的方式仅锁住当前正在操作的数组桶其余桶可以多线程同时读写1.2 null‑value规则HashMap: 允许使用1个null来作为主键,可以存放多个null值HashTable: K,V两个值都禁止使用null值,否则编译器会抛出NullPointerException异常例如:3. ConcurrentHashMap: 同样K,V值不支持使用null,否则抛出NullPointerException异常1.3 默认容量、扩容、底层数据结构HashMap初始容量为16,负载因子0.75,扩容方式采用2倍扩容当满足条件时,链表会转化成红黑树HashTable初始容量:11负载因子:0.75扩容规则:newCapacity oldCapacity * 2 1不会转化成红黑树ConcurrentHashMap初始容量:16负载因子:0.75JDK8中依旧只有数组和链表的形式,不会转化成红黑树JDK8以后,ConcurrentHashMap具备转化成红黑树的能力; 返回目录2. 底层细节区分2.1 HashTable为什么现在不推荐使用?上诉谈到:HashTable是线程安全的,但是在实际开发中并不怎么使用HashTable,理由如下:假设:我们两个以及以上的线程需要修改很多次HashTable中的数据;当很多个线程在没有锁的情况下去修改同一个数据的时候,会触发线程安全问题;此时很多个线程同时操作当前哈希表中相同一个链表的数据,由于有锁此时不会发生线程安全问题;但是此时如果很多条线程操作不同链表中的数据,此时这把锁还需要上吗?我们知道,就算此时就算不加锁,也不会触发线程安全问题,如果链表中有很多数据,另外两条线程拿不到锁就会一直处于阻塞状态,不会执行,就会减少执行的效率2.2 ConcurrentHashMap相较于HashTable优势相较于:HashTable,ConcurrentHashMap大幅度提升了执行效率:JDK7Segment分段锁ConcurrentHashMap采用了给哈希表的每一个节点进行上锁,每一把锁对应不同的链表当不同线程去访问不同链表时,不会进行阻塞,访问同一条链表时,就会进行阻塞等待;JDK8彻底废弃Segment改用Node桶节点锁和CAS自旋。当准备修改桶内数据仅锁住链表头部节点。(CAS自旋,compare and swap,比较并交换,CAS也属于解决线程安全的一种手段,此处不具体讲解CAS);好处锁粒度细化到每一个哈希桶并发吞吐量大幅度提升。 返回目录3. 面试高频问答题库HashMap 在多线程环境为什么不安全JDK7头插法扩容容易产生环形链表然后就会触发死循环多个线程同时执行put操作时会发生value值覆盖丢失。 JDK8改成尾插解决环形链表但依旧存在并发写入覆盖问题。ConcurrentHashMap 相较于 HashTable 的性能优势HashTable 锁住是整张哈希数组ConcurrentHashMap 只锁定当前操作的桶结点其余位置可以并发读写冲突概率很低高并发场景性能远超 HashTable。为什么 ConcurrentHashMap 的 value 不能等于 null并发读取的时候get (key) 返回 null你没办法区分是该 key 不存在还是 key 对应的存储值就是 null。单线程可以二次调用 containsKey 判断并发情况下两次调用之间数据随时会被别的线程改动判断失效。 返回目录
返回列表