HashMap 和 Hashtable 都是常用的用于查询键值对的数据结构,它们非常相似,但存在一些差别:
区别:
1. 线程安全性:Hashtable 是线程安全的,因为它的所有方法都是同步的(synchronized),而 HashMap 不是线程安全的。简单来说,Hashtable 中的操作不会出现线程问题,但是 HashMap 会出现,当多个线程对一个 HashMap 进行操作时可能会出现数据不正确的情况。
2.效率:由于 Hashtable 的所有方法都是同步的,因此在单线程环境下,HashMap 的性能会优于 Hashtable,但在多线程环境下,由于线程同步的开销,Hashtable 的性能会优于 HashMap。
3.键和值可以为 null:HashMap 允许键和值都为 null,而 Hashtable 不允许。
4. 初始容量和加载因子:Hashtable 的初始容量为11,而 HashMap 的初始容量为16。Hashtable 的加载因子为0.75,而 HashMap 的加载因子为0.75。
优势:
HashMap:它是一种无序键值对集合,它最大的优势在于当数据量较大时,它的查询速度非常快,复杂度为 O(1)。
Hashtable:由于在多线程环境下不会出现数据不正确的情况,因此它通常用于并发修改操作时。Hashtable 也是一种非常古老的数据结构,其稳定、可靠的特性常常被人们所信任和使用。
缺点:
HashMap 的缺点在于它是无序的,因此如果需要按照键值排序输出,需要将其转化为 Collection 后再进行排序。同时,由于它不是线程安全的,因此在多线程环境中需要进行类似于 ConcurrentHashMap 的封装,以避免出现数据不正确的情况。
Hashtable 的缺点在于它是同步的,因此在单线程模式或性能要求较高的场景中使用 Hashtable 可能会导致性能下降。同时,Hashtable 的初始容量和扩容机制不够智能,可能会浪费一些内存空间。
那么,HashMap 是线程不安全的,那么在需要线程安全的情况下 还要考虑性能,有什么解决方式?
在需要线程安全且具有良好性能的情况下,可以使用 ConcurrentHashMap 来替代 HashMap。ConcurrentHashMap 是 JDK 提供的线程安全的哈希表实现,使用了分段锁技术,因此在高并发环境下比 Hashtable、Collections.synchronizedMap()、ConcurrentSkipListMap 等具有更好的性能表现。
与 HashMap 不同的是,ConcurrentHashMap 的实现是将 Map 分成若干个 Segment,每个线程对于不同的 Segment 拥有独立的锁,并发安全地修改哈希表,从而大大提高了线程安全和并发能力,同时也保证了较好的查询性能。
使用 ConcurrentHashMap 需要注意以下几点:
1. ConcurrentHashMap 的初始化容量和负载因子与 HashMap 相同,但不同的是 ConcurrentHashMap 默认创建16个 Segment,可以通过构造方法指定 Segment 数量。
2. ConcurrentHashMap 适合于高并发的环境,如果并发量比较小,建议还是使用 HashMap。
3. 在使用 ConcurrentHashMap 的时候需要注意每次读写操作的安全性,例如 remove 和 put 操作的顺序问题。