JAVA:多线程使用哈希表
HashMap
线程安全性
线程不安全,无任何同步机制。多线程在读写情况下可能出现数据不一致的情况
底层结构
JDK 1.7及之前用的是数组加链表
JDK1.8 优化成了数组加链表加红黑树
当链表长度超过阈值就会转换成红黑树,提升查找效率。
null支持
允许键和值都为null, 但是键只能有一个为null,注意HashMap的键具有唯一性;因为null的哈希值计算特殊,通常存储在数组的第一个位置附近。
性能
单线程或者线程安全时,读写性能优秀。哈希算法可进行快速定位,链表或者红黑树处理冲突,平均的时间复杂度接近O(1)
HashTable
线程安全性
是线程安全的,通过给方法添加 synchronized 锁实现,因为给方法加锁的缘故,每个方法在同一时间只允许一个线程执行,虽然保证了数据的安全性,但在多线程的情况下性能较差。
底层结构
数据结构采用数组加链表的形式,通过哈希算法确定元素的位置,哈希冲突时用链表解决。
null支持
不允许键或值为null ,如果尝试插入null 会直接抛异常。HashTable 内部代码对 null 做了严格的检查。
性能
多线程环境下,线程竞争锁激烈,读写性能低下;若单线程使用还有锁的开销不如直接用HashMap,基本已经被淘汰
ConcurrentHashMap
线程安全性
是线程安全的,采用优化的锁策略, 跟HashTable 不同的是锁粒度更细,并发性能更高。
底层结构
JDK 1.7 也是数组加链表的形式,将数组元素分组去加锁;在JDK1.8 采用数组加链表加红黑树的形式,对每个数组元素加锁。通过CAS与锁保证多线程下的数据一致性。
null支持
不允许键或值为null,在多线程中,null可能会导致歧义,例如无法区分是初始化的null 还是插入的null。
性能
多线程并发读写性能优越,读操作几乎无锁,写操作锁粒度更细,减少了线程竞争,在高并发场景性能接近HashMap。
总结
名称 | HashMap | HashTable | ConcurrentHashMap |
线程安全性 | 非线程安全 | 线程安全 | 线程安全 |
底层结构 | JDK1.7数组+链表 JDK1.8数组+链表+红黑树 | 数组+链表 | JDK1.7数组+链表 JDK1.8数组+链表+红黑树 |
null支持 | 允许键值为null | 不允许键值为null | 不允许键值为null |
性能 | 单线程性能优,多线程不安全 | 多线程性能差 | 多线程性能优 |