HashMap、HashTable及ConcurrentHashMap的区别及线程安全问题

HashMap和HashTable的比较:

区别:

1,HashMap的键值都可以是null,HashTable都不可以,所以HashMap中多用contains(key)这个方法判断是否存在这个key

2,HashTable中存在synchronized,存在同步锁,这就是区分两者线程是否安全的关键

3,HashMap中迭代器是fail-fast迭代器,HashTable为fail-safe迭代器。

注:fail-safe允许在遍历的过程中对容器中的数据进行修改,而fail-fast则不允许。

fail-fast:直接在容器上进行遍历,在遍历过程中,一旦发现容器中的数据被修改了,会立刻抛出ConcurrentModificationException异常导致遍历失败。常见的的使用fail-fast方式遍历的容器有HashMap和ArrayList等。

fail-safe:这种遍历基于容器的一个克隆。因此,对容器内容的修改不影响遍历。常见的的使用fail-safe方式遍历的容器有ConcerrentHashMap和CopyOnWriteArrayList等。

4,HashTable保证了线程安全,所以运行速度相对会慢一些

相同点:

1.都是插入后扩容,扩容触发条件为当前有效村粗数组的hash值个数超过总容量75/100(默认为75/100)

2. HashTable和HashMap的底层实现均是数组 + 链表
HashTable的初始化 size = 11,扩容 newsize = oldsize2 + 1,
计算index的方式是 index = (hash & 0x7FFFFFFF) % tab.length。
HashMap的初始化 szie = 16, 扩容 newsize = 2oldsize(size是2的 n 次方),
计算index的方式是 index = hash & (tab.length – 1)
 

ConcurrentHashMap:

是对HashMap的优化,线程安全,使用了锁,并且是分段锁

1.底层实现是链表+分段数组

2.默认将Map分为16片(segment,可调)

3. ConcurrentHashMap是插入前扩容,即插入前检查当前有效存储数组的hash值个数是否超过负载因子(默认为总容量的75%),若超过,再扩容

 

注:分段锁:

是一种锁的设计,并不是具体的一种锁,对于ConcurrentHashMap而言,其并发的实现就是通过分段锁的形式来实现高效的并发操作。

ConcurrentHashMap中的分段锁称为Segment,它即类似于HashMap(JDK7与JDK8中HashMap的实现)的结构,即内部拥有一个Entry数组,数组中的每个元素又是一个链表;同时又是一个ReentrantLock(Segment继承了ReentrantLock)。

当需要put元素的时候,并不是对整个hashmap进行加锁,而是先通过hashcode来知道他要放在那一个分段中,然后对这个分段进行加锁,所以当多线程put的时候,只要不是放在一个分段中,就实现了真正的并行的插入。

但是,在统计size的时候,可就是获取hashmap全局信息的时候,就需要获取所有的分段锁才能统计。

分段锁的设计目的是细化锁的粒度,当操作不需要更新整个数组的时候,就仅仅针对数组中的一项进行加锁操作。

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值