HashMap、Hashtabl、ConcurrentHashMap的区别

HashMap、Hashtabl、ConcurrentHashMap的区别


作为面试必问问题,还是非常有必要去深入学习一下它们之间的区别,有时间最好去读下源码。

HashMap

  • jdk1.7底层使用数组+单链表的形式存储数据,而jdk1.8是用数组+单链表+红黑树存储数据。
  • 读写方法都没加锁,所以是非线程安全的。
  • 可以存储key和value为null的元素。
  • 初始容量DEFAULT_INITIAL_CAPACITY=16。
  • 默认负载因子 loadFactor=DEFAULT_LOAD_FACTOR = 0.75f
  • 扩容条件为:(size >= threshold) && (null != table[bucketIndex]),其中threshold是临界值threshold=Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
  • 扩容函数resize(),阔容大小:newCapacity = 2 * table.length,即两倍阔容,且容量一定为2的n次幂。
  • 扩容针对整个Map,每次扩容时,通过transfer()将原来数组中的元素依次重新计算存放位置,并重新插入。
  • 计算index的方法indexFor():index = hash & (tab.length – 1).

Hashtable

  • 是由数组+单链表方式实现。
  • 在对外的函数上加了synchronized重入锁,而且锁的是Entry<?,?>[] table的全部数据,所以是线程安全的。
  • 键和值都不能null
  • 默认的初始容量为11,负载因子为0.75f.
  • 扩容条件:count >= threshold,count记录容器中实际存储的数量,等价于HashMap中size。
  • 每次使用rehash() 方法扩容,扩容大小:newCapacity = (oldCapacity << 1) + 1,每次进行两倍+1扩容。
  • 扩容针对整个Map,每次扩容时,直接在rehash()将原来数组中的元素依次重新计算存放位置,并重新插入。
  • 计算index的方法:index = (hash & 0x7FFFFFFF) % tab.length。

ConcurrentHashMap

  • 存储方式和HashMap一样。

  • 通过把整个Map分为N个Segment,通过用ReentrantLock重入锁对写操作的segmet加锁,来保证线程安全,但是效率提升N倍,默认提升16倍。(读操作不加锁,由于HashEntry的value变量是 volatile的,也能保证读取到最新的值。)

  • 键和值都不能null。

  • Hashtable的synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术。

  • 有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁。

锁分段技术

首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。

ConcurrentHashMap提供了与Hashtable和SynchronizedMap不同的锁机制。Hashtable中采用的锁机制是一次锁住整个hash表,从而在同一时刻只能由一个线程对其进行操作;而ConcurrentHashMap中则是一次锁住一个桶。

ConcurrentHashMap默认将hash表分为16个桶,诸如get、put、remove等常用操作只锁住当前需要用到的桶。这样,原来只能一个线程进入,现在却能同时有16个写线程执行,并发性能的提升是显而易见的。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
HashMapConcurrentHashMap都是Java中的Map接口的实现,它们之间有以下几点区别: 1. 线程安全性:HashMap是非线程安全的,而ConcurrentHashMap是线程安全的。在多线程环境下,多个线程可以同时对ConcurrentHashMap进行读写操作,而不会导致数据不一致或者抛出异常。 2. 锁机制:HashMap使用的是悲观锁机制,即在进行写操作时需要对整个HashMap进行加锁,这样会导致并发性能下降。而ConcurrentHashMap使用的是分段锁(Segment),将整个Map分成多个段(Segment),每个段都有一个独立的锁,不同的线程可以同时对不同的段进行操作,从而提高并发性能。 3. 迭代器弱一致性:在HashMap中,如果在迭代过程中对HashMap进行修改,可能会导致ConcurrentModificationException异常。而ConcurrentHashMap的迭代器是弱一致性的,它不会抛出ConcurrentModificationException异常,但是不能保证迭代器返回的元素是最新的。 4. 初始化容量和扩容机制:HashMap在初始化时需要指定初始容量,并且在容量不足时会进行扩容。而ConcurrentHashMap可以在初始化时不指定初始容量,默认为16,并且在扩容时只对部分段进行扩容,而不是整个Map。 5. 性能:在单线程环境下,HashMap的性能可能会略优于ConcurrentHashMap,因为ConcurrentHashMap需要维护额外的线程安全机制。但在多线程环境下,ConcurrentHashMap的性能通常会优于HashMap
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值