【面朝大厂】最常见的15道 ConcurrentHashMap 面试题解答

点击上方“Java基基”,选择“设为星标”

做积极的人,而不是积极废人!

每天 14:00 更新文章,每天掉亿点点头发...

源码精品专栏

 

来源:blog.csdn.net/xt199711
/article/details/114339022


1 ConcurrentHashMap默认初始容量是多少?

从下面ConcurrentHashMap类的静态变量可以看出它的初始容量为16

推荐下自己做的 Spring Boot 的实战项目:

https://github.com/YunaiV/ruoyi-vue-pro

2 ConCurrentHashmap 的key,value是否可以为null。

不行 如果key或者value为null会抛出空指针异常

推荐下自己做的 Spring Cloud 的实战项目:

https://github.com/YunaiV/onemall

3 ConCurrentHashmap 每次扩容是原来容量的几倍

2倍 在transfer方法里面会创建一个原数组的俩倍的node数组来存放原数据。

4 ConCurrentHashmap的数据结构是怎么样的?(后面会具体分析它的put方法)

在java1.8中,它是一个数组+链表+红黑树的数据结构。

5 存储在ConCurrentHashmap中每个节点是什么样的,有哪些变量

它是实现Map.Entry<K,V>接口。里面存放了hash,key,value,以及next节点。它的value和next节点是用volatile进行修饰,可以保证多线程之间的可见性。

6 ConCurrentHashmap的put过程是怎样的?

整体流程跟HashMap比较类似,大致是以下几步:

  • 如果桶数组未初始化,则初始化;

  • 如果待插入的元素所在的桶为空,则尝试把此元素直接插入到桶的第一个位置;

  • 如果正在扩容,则当前线程一起加入到扩容的过程中;

  • 如果待插入的元素所在的桶不为空且不在迁移元素,则锁住这个桶(分段锁);

  • 如果当前桶中元素以链表方式存储,则在链表中寻找该元素或者插入元素;

  • 如果当前桶中元素以红黑树方式存储,则在红黑树中寻找该元素或者插入元素;

  • 如果元素存在,则返回旧值;

  • 如果元素不存在,整个Map的元素个数加1,并检查是否需要扩容;

添加元素操作中使用的锁主要有(自旋锁 + CAS + synchronized + 分段锁)。

7 java1.8中ConCurrentHashmap节点是尾插还是头插?

尾插法,见上述put方法。

8 java1.8中,ConCurrentHashmap什么情况下链表才会转换成红黑树进行存储?

链表长度大于8。数组长度大于64。从put源码和以下源码可以看出:并非一开始就创建红黑树结构,如果当前Node数组长度小于阈值MIN_TREEIFY_CAPACITY,默认为64,先通过扩大数组容量为原来的两倍以缓解单个链表元素过大的性能问题。

9 java1.8中,ConCurrentHashmap的get过程是怎样的?

  • 计算 hash 值

  • 根据 hash 值找到数组对应位置: (n - 1) & h

  • 根据该位置处结点性质进行相应查找

如果该位置为 null,那么直接返回 null 就可以了

如果该位置处的节点刚好就是我们需要的,返回该节点的值即可

如果该位置节点的 hash 值小于 0,说明正在扩容,或者是红黑树,后面我们再介绍 find 方法如果以上 3 条都不满足,那就是链表,进行遍历比对即可

10 java1.8中,ConCurrentHashmap是如何计算它的size大小的?

对于size的计算,在扩容和addCount()方法就已经有处理了,可以注意一下Put函数,里面就有addCount()函数。

11 ConcurrentHashMap有哪些构造函数?

一共有五个,作用及代码如下:

//无参构造函数
public ConcurrentHashMap() {
        }
//可传初始容器大小的构造函数
public ConcurrentHashMap(int initialCapacity) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException();
            int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
            MAXIMUM_CAPACITY :
            tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));
            this.sizeCtl = cap;
        }
//可传入map的构造函数
public ConcurrentHashMap(Map<? extends K, ? extends V> m) {
            this.sizeCtl = DEFAULT_CAPACITY;
            putAll(m);
        }
//可设置阈值和初始容量
public ConcurrentHashMap(int initialCapacity, float loadFactor) {
            this(initialCapacity, loadFactor, 1);
        }

//可设置初始容量和阈值和并发级别
public ConcurrentHashMap(int initialCapacity,
        float loadFactor, int concurrencyLevel) {
        if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0)
            throw new IllegalArgumentException();
        if (initialCapacity < concurrencyLevel)   // Use at least as many bins
            initialCapacity = concurrencyLevel;   // as estimated threads
            long size = (long)(1.0 + (long)initialCapacity / loadFactor);
            int cap = (size >= (long)MAXIMUM_CAPACITY) ?
                MAXIMUM_CAPACITY : tableSizeFor((int)size);
            this.sizeCtl = cap;
        }

12 ConcurrentHashMap使用什么技术来保证线程安全?

jdk1.7:Segment+HashEntry来进行实现的;

jdk1.8:放弃了Segment臃肿的设计,采用Node+CAS+Synchronized来保证线程安全;

13 ConcurrentHashMap的get方法是否要加锁,为什么?

不需要,get方法采用了unsafe方法,来保证线程安全。

14 ConcurrentHashMap迭代器是强一致性还是弱一致性?HashMap呢?

弱一致性,HashMap强一直性。

ConcurrentHashMap可以支持在迭代过程中,向map添加新元素,而HashMap则抛出了ConcurrentModificationException,因为HashMap包含一个修改计数器,当你调用他的next()方法来获取下一个元素时,迭代器将会用到这个计数器。

15 ConcurrentHashMap1.7和1.8的区别

jdk1.8的实现降低锁的粒度,jdk1.7锁的粒度是基于Segment的,包含多个HashEntry,而jdk1.8锁的粒度就是Node

数据结构:jdk1.7 Segment+HashEntry;jdk1.8 数组+链表+红黑树+CAS+synchronized



欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢

ef5f27b03d5cc784efbe15143ff2fe83.png

已在知识星球更新源码解析如下:

f1f266f9dd5b820858b69b27207d1214.png

99c8e954368bbae7ea54e1e69ca1cb77.png

cfe48d5fe0eb8cd8ef958430ec7ec730.png

102d0a979ebdcdcc71af832e3b01b282.png

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 6W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一些可能被问到的concurrentHashmap面试题: 1. 什么是ConcurrentHashMapConcurrentHashMapJava的一个线程安全的哈希表。它是由多个分离的桶组成的,每个桶都可以被独立地锁住,从而使得多个线程可以同时访问不同的桶,从而提高了并发性能。 2. ConcurrentHashMapHashMap有什么区别? ConcurrentHashMap是线程安全的,而HashMap是非线程安全的。ConcurrentHashMap内部使用了分离的桶和锁机制来保证线程安全性,并且多个线程可以同时进行读取操作,而HashMap则没有这样的机制。 3. ConcurrentHashMap的实现原理是什么? ConcurrentHashMap内部使用了分离的桶和锁机制来保证线程安全性。每个桶都有一个独立的锁,多个线程可以同时访问不同的桶,从而提高了并发性能。同时,ConcurrentHashMap还使用了一种被称为“分段锁”的机制,即将整个哈希表分为多个段,每个段都有一个独立的锁来保证线程安全。 4. ConcurrentHashMap如何保证线程安全性? ConcurrentHashMap使用了分离的桶和锁机制来保证线程安全性。每个桶都有一个独立的锁,多个线程可以同时访问不同的桶,从而提高了并发性能。同时,ConcurrentHashMap还使用了一种被称为“分段锁”的机制,即将整个哈希表分为多个段,每个段都有一个独立的锁来保证线程安全。 5. ConcurrentHashMap的性能如何? ConcurrentHashMap的性能非常好,尤其是在高并发环境下。由于它使用了分离的桶和锁机制,可以同时进行读取操作,从而大幅度提高了读取性能。同时,它还使用了分段锁机制来保证线程安全性,这也进一步提高了并发性能。 6. ConcurrentHashMap的缺点是什么? ConcurrentHashMap的主要缺点是占用内存较大,因为它需要维护多个分离的桶和锁。此外,由于它使用了分段锁机制,所以在进行写操作时可能会出现锁竞争,导致性能下降。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值