美文网首页
ConcurrentHashMap常问问题

ConcurrentHashMap常问问题

作者: 坤坤坤坤杨 | 来源:发表于2022-04-06 17:22 被阅读0次

1. ConcurrentHashMap的原理

1.1 JDK1.7的ConcurrentHashMap

采用了分段锁的思想,将哈希桶数组分成一个个的Segment数组(继承ReentrantLock),每一个Segment里面又有多个HashEntry,也是被volatile修饰的,是为了保证在数组扩容时候的可见性,HashEntry中又有key,hash,value,next属性,而value,next又是被volatile修饰为了保证多线程环境下数据修改时的可见性,多线程环境下ConcurrentHashMap会对这些小的数组进行加锁,这样多线程操作Map就相当于是操作单线程环境下的HashMap,比如A线程对其中一个段进行写操作的时候线程B就不能对其进行写操作,但是线程B可以对其他的段进行写操作,从而实现并发修改和访问。

1.2 JDK1.8的ConcurrentHashMap

JDK1.8的ConcurrentHashMap摒弃了分段锁的思想,采用jdk1.8中HashMap的底层机构,Node数组+链表+红黑树。Node是继承了Entry的一个内部类,他的value和next都是被volatile修饰的原因也是为了保证多线程下修改数据的可见性。

采用CAS+synchronized实现更加细粒度的锁,将锁的级别控制在更细粒度的哈希桶数组元素的级别,只需要锁住链表头节点(红黑树的根节点)就不会影响到其他哈希桶数组元素的读写,大大的提高了并发度。

2. ConcurrentHashMap的get方法需要加锁吗?

是不需要加锁的,因为Node节点使用了volatile修饰了value和next节点,而在jdk8中同样也是使用了volatile修饰了value和next节点,这样保证可见性了就不需要加锁了。

1.3 1.7和1.8中ConcurrentHashMap的区别

  1. 数据结构:1.7中底层是使用Segment数组+链表的结构,1.8中采用了Node数组+链表+红黑树的结构。
  2. 查询复杂度:1.7遍历链表为O(N)而1.8变成红黑树后的复杂度为O(logN)。
  3. 保证线程安全的机制:1.7采用分段锁机制实现线程安全,其中Segment继承自ReentrantLock。1.8采用了CAS+synchronized保证线程安全,因此也引出了锁粒度上的区别。
  4. 锁粒度:1.7是对需要进行数据操作的Segment加锁,1.8是调整为每个数组元素的头节点加锁。

3. ConcurrentHashMap不支持key或者value为空的原因?

key不能为空,无法解释,没有什么可说的,可能就是作者的想法。
value不能为空是因为ConcurrentHashMap是工作在多线程环境下的,如果调用get方法,返回null,这个时候就存在二义性,因为ConcurrentHashMap不知道是没有这个key,还是这个key对应的值是不是null。所以干脆不支持value为null。

4. ConcurrentHashMap的迭代器是强一致性还是弱一致性?

HashMap的迭代器是强一致性的,而ConcurrentHashMap的迭代器是弱一致性的,因为在多线程环境下,在创建迭代器的过程中,内部的元素会发生变化,如果是在已经遍历过去的数据中发生变化,迭代器是无法反映出来数据发生了改变,如果是发生在未迭代的数据时,这个时候就会反映出来,强一致性就是说只要迭代器创建出来之后数据就不会发生改变了。这样设计的好处就是迭代器线程可以使用原来的老数据进行遍历,写线程可以并发的完成改变,这样就保证了多个线程执行的时候的连续性和可拓展性,提升了并发性能。

5. JDK1.8中为什么使用synchronized替换ReentrantLock?

  1. 性能:因为是synchronized在jdk1.6引入了大量的优化,如锁升级,锁粗化,锁消除,自旋锁,自适应自旋锁等的优化,本身的性能得到了提升。
  2. 并发度和内存开销:CAS+synchronized方式时加锁的对象是每个链条的头节点,相对Segment再次提高了并发度,如果使用可重入锁达到同样的效果的话,则需要大量继承自ReentrantLock的对象,造成巨大的内存浪费。

6. ConcurrentHashMap的并发度是如何设计的?

并发度可以理解为程序运行时能够同时更新ConcurrentHashMap且不产生锁竞争的最大线程数。

JDK1.7中,并发度就是ConcurrentHashMap中的分段个数,即Segment[]数组的长度,默认是16,这个值可以在构造函数中设置。如果自己设置了并发度那么就会和HasHMap一样会去找到大于等于当前输入值的最小的2的幂指数作为实际并发度。如果过小就会产生锁竞争,如果过大,那么就会导致本来位于同一个Segment的的访问会扩散到不同的Segment中,导致性能下降。
JDK1.8中摈弃了Segment的概念,选择使用HashMap的结构,并发度依赖于数组的大小。

7. ConcurrentHashMap和hashTable的效率哪一个高?为什么?

ConcurrentHashMap效率高,因为hashTable是给整个hash表加锁,而ConcurrentHashMap锁粒度要更低。

8. 还有什么其他方式可以在多线程情况下操作Map?

使用Collections.synchronizedMap(Map类型的对象)方法进行同步加锁,把对象转换为SynchronizedMap<K,V>类型。其实就是对HashMap做了一次封装,多个线程竞争一个mutex对象锁,在竞争激烈的情况下性能也非常差,不推荐使用。

相关文章

  • ConcurrentHashMap常问问题

    1. ConcurrentHashMap的原理 1.1 JDK1.7的ConcurrentHashMap 采用了分...

  • 常问问题

    1.如何理解闭包?用途?举个例子?2.原型、函数扩展?3.apply 与call 区别?4.原型链、链式操作原理?...

  • Java面试常问问题

    一:阿里技术一面(基础掌握牢固) 常用的异常类型? session java锁 gc原理 hashmap list...

  • PHP面试常问问题

    PHP变量类型: Boolean 布尔类型 Integer 整型 Float 浮点型 String 字符串 Arr...

  • TCP/IP常问问题

    OSI与TCP/IP各层的结构与功能,都有哪些协议。Done TCP与UDP的区别。Done TCP报文结构。Do...

  • MySQL面试常问问题

    1.mysql事务特征 答:原子性,一致性,隔离性,持久性。 2.mysql索引是怎么实现的 答:数据库索引通常使...

  • 答辩常问问题文档

    如何实现前后台数据传输?使用http通信实现的了前后台数据传输,客户端发送http请求到服务器端,服务器端根据请求...

  • hashmap 面试常问问题

    1:HashMap 的数据结构? A:哈希表结构(链表散列:数组+链表)实现,结合数组和链表的优点。当链表长度超过...

  • ConcurrentHashMap 1.8 较 1.7 的改变

    HashTable -> ConcurrentHashMap 1.7 -> ConcurrentHashMap 1...

  • ConCurrentHashMap了解一下

    前言 ConcurrentHashMap 1.7 ConcurrentHashMap 1.8 Concurrent...

网友评论

      本文标题:ConcurrentHashMap常问问题

      本文链接:https://www.haomeiwen.com/subject/wtmrsrtx.html