HashTable, HashMap, ConcurrentHashMap 之间的区别

HashMap本身不是线程安全的.

在多线程环境下使用哈希表可以使用:

  • Hashtable
  • ConcurrentHashMap

一.Hashtable

Hashtable只是简单的把关键方法加上了synchronized关键字.

这相当于直接针对Hashtable对象本身加锁.

  • 如果多线程访问同一个Hashtable就会直接造成锁冲突.
  • size属性也是通过synchronized来控制同步,也是比较慢的.
  • 一旦触发扩容,就由该线程完成整个扩容过程,这个过程会涉及到大量的元素拷贝,效率会非常低.

一个Hashtable只有一把锁.两个线程访问Hashtable中的任意数据都会出现锁竞争.

二.ConcurrentHashMap

相比于Hashtable做出了一系列的改进和优化.以java1.8为例:

  • 读操作没有加锁(但是使用了volatile保证从内存读取结果),只对写操作进行加锁,加锁的方式任然时使用synchronized,但是不是锁整个对象,而是"锁桶"(用每个链表的头节点作为锁对象),大大降低了锁冲突的概率.
  • 充分利用了CAS特性.比如size属性通过CAS来更新.避免出现重量级锁的情况.
  • 优化了扩容方式:化零为整

                 1)发现需要扩容的线程,只需要创建一个新的数组,同时只搬几个元素过去.

                  2)扩容期间,新老数组同时存在.

                  3)后续每个来操作ConcurrentHashtableMap的线程,都会参与搬家的过程,每个操作负责搬运一小部分元素.

                 4)搬完最后一个元素再把老数组删掉

                 5)这个期间,插入只往新数组加.

                 6)这个期间,查找需要同时查新数组和老数组.

ConcurrentHashMap每个哈希桶都有一把锁.只有两个线程访问地 恰好时同一个哈希桶上的数据才出现锁冲突

三.相关面试题

3.1 ConcurrentHashMap的读是否要加锁,为什么?


读操作没有加锁,目的是为了进一步降低锁冲突的概率。为了保证读到刚修改的数据, 搭配了
volatile 关键字


3.2 ConcurrentHashMap的锁分段技术?
简单的说就是把若干个哈希桶分成一个 "段" (Segment), 针对每个段分别加锁。目的也是为了降低锁竞争的概率,当两个线程访问的数据恰好在同一个段上的时候, 才触发锁竞争。


3.3 ConcurrentHashMap在jdk1.8做了哪些优化? 
取消了分段锁, 直接给每个哈希桶(每个链表)分配了一个锁(就是以每个链表的头结点对象作为锁对象)。
将原来数组 + 链表的实现方式改进成 数组 + 链表 / 红黑树 的方式,当链表较长的时候(大于等于8 个元素)就转换成红黑树。


 3.4 Hashtable和HashMap、ConcurrentHashMap 之间的区别?
HashMap: 线程不安全,key 允许为 null
Hashtable: 线程安全。使用 synchronized 锁 Hashtable 对象, 效率较低。 key 不允许为 null
ConcurrentHashMap: 线程安全。使用 synchronized 锁每个链表头结点, 锁冲突概率低, 充分利用CAS 机制, 优化了扩容方式, key 不允许为 null

  • 27
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值