【Java自顶向下】ConcurrentHashMap面试题(2021最新版)
文章目錄
- 1 ConcurrentHashMap默認(rèn)初始容量是多少?
- 2 ConCurrentHashmap 的key,value是否可以為null。
- 3 ConCurrentHashmap 每次擴(kuò)容是原來容量的幾倍
- 4 ConCurrentHashmap的數(shù)據(jù)結(jié)構(gòu)是怎么樣的?(后面會(huì)具體分析它的put方法)
- 5 存儲(chǔ)在ConCurrentHashmap中每個(gè)節(jié)點(diǎn)是什么樣的,有哪些變量
- 6 ConCurrentHashmap的put過程是怎樣的?
- 7 java1.8中ConCurrentHashmap節(jié)點(diǎn)是尾插還是頭插?
- 8 java1.8中,ConCurrentHashmap什么情況下鏈表才會(huì)轉(zhuǎn)換成紅黑樹進(jìn)行存儲(chǔ)?
- 9 java1.8中,ConCurrentHashmap的get過程是怎樣的?
- 10 java1.8中,ConCurrentHashmap是如何計(jì)算它的size大小的?
- 11 ConcurrentHashMap有哪些構(gòu)造函數(shù)?
- 12 ConcurrentHashMap使用什么技術(shù)來保證線程安全?
- 13 ConcurrentHashMap的get方法是否要加鎖,為什么?
- 14 ConcurrentHashMap迭代器是強(qiáng)一致性還是弱一致性?HashMap呢?
- 15 ConcurrentHashMap1.7和1.8的區(qū)別
1 ConcurrentHashMap默認(rèn)初始容量是多少?
從下面ConcurrentHashMap類的靜態(tài)變量可以看出它的初始容量為16
2 ConCurrentHashmap 的key,value是否可以為null。
不行 如果key或者value為null會(huì)拋出空指針異常
3 ConCurrentHashmap 每次擴(kuò)容是原來容量的幾倍
2倍 在transfer方法里面會(huì)創(chuàng)建一個(gè)原數(shù)組的倆倍的node數(shù)組來存放原數(shù)據(jù)。
4 ConCurrentHashmap的數(shù)據(jù)結(jié)構(gòu)是怎么樣的?(后面會(huì)具體分析它的put方法)
在java1.8中,它是一個(gè)數(shù)組+鏈表+紅黑樹的數(shù)據(jù)結(jié)構(gòu)。
5 存儲(chǔ)在ConCurrentHashmap中每個(gè)節(jié)點(diǎn)是什么樣的,有哪些變量
它是實(shí)現(xiàn)Map.Entry<K,V>接口。里面存放了hash,key,value,以及next節(jié)點(diǎn)。它的value和next節(jié)點(diǎn)是用volatile進(jìn)行修飾,可以保證多線程之間的可見性。
6 ConCurrentHashmap的put過程是怎樣的?
整體流程跟HashMap比較類似,大致是以下幾步:
(1)如果桶數(shù)組未初始化,則初始化;
(2)如果待插入的元素所在的桶為空,則嘗試把此元素直接插入到桶的第一個(gè)位置;
(3)如果正在擴(kuò)容,則當(dāng)前線程一起加入到擴(kuò)容的過程中;
(4)如果待插入的元素所在的桶不為空且不在遷移元素,則鎖住這個(gè)桶(分段鎖);
(5)如果當(dāng)前桶中元素以鏈表方式存儲(chǔ),則在鏈表中尋找該元素或者插入元素;
(6)如果當(dāng)前桶中元素以紅黑樹方式存儲(chǔ),則在紅黑樹中尋找該元素或者插入元素;
(7)如果元素存在,則返回舊值;
(8)如果元素不存在,整個(gè)Map的元素個(gè)數(shù)加1,并檢查是否需要擴(kuò)容;
添加元素操作中使用的鎖主要有(自旋鎖 + CAS + synchronized + 分段鎖)。
7 java1.8中ConCurrentHashmap節(jié)點(diǎn)是尾插還是頭插?
尾插法,見上述put方法。
8 java1.8中,ConCurrentHashmap什么情況下鏈表才會(huì)轉(zhuǎn)換成紅黑樹進(jìn)行存儲(chǔ)?
鏈表長(zhǎng)度大于8。數(shù)組長(zhǎng)度大于64。從put源碼和以下源碼可以看出:并非一開始就創(chuàng)建紅黑樹結(jié)構(gòu),如果當(dāng)前Node數(shù)組長(zhǎng)度小于閾值MIN_TREEIFY_CAPACITY,默認(rèn)為64,先通過擴(kuò)大數(shù)組容量為原來的兩倍以緩解單個(gè)鏈表元素過大的性能問題。
9 java1.8中,ConCurrentHashmap的get過程是怎樣的?
1、計(jì)算 hash 值
2、根據(jù) hash 值找到數(shù)組對(duì)應(yīng)位置: (n - 1) & h
3、根據(jù)該位置處結(jié)點(diǎn)性質(zhì)進(jìn)行相應(yīng)查找
如果該位置為 null,那么直接返回 null 就可以了
如果該位置處的節(jié)點(diǎn)剛好就是我們需要的,返回該節(jié)點(diǎn)的值即可
如果該位置節(jié)點(diǎn)的 hash 值小于 0,說明正在擴(kuò)容,或者是紅黑樹,后面我們?cè)俳榻B find 方法如果以上 3 條都不滿足,那就是鏈表,進(jìn)行遍歷比對(duì)即可
10 java1.8中,ConCurrentHashmap是如何計(jì)算它的size大小的?
對(duì)于size的計(jì)算,在擴(kuò)容和addCount()方法就已經(jīng)有處理了,可以注意一下Put函數(shù),里面就有addCount()函數(shù)。
11 ConcurrentHashMap有哪些構(gòu)造函數(shù)?
一共有五個(gè),作用及代碼如下:
//無參構(gòu)造函數(shù)public ConcurrentHashMap() {}//可傳初始容器大小的構(gòu)造函數(shù)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的構(gòu)造函數(shù)public ConcurrentHashMap(Map<? extends K, ? extends V> m) {this.sizeCtl = DEFAULT_CAPACITY;putAll(m);}//可設(shè)置閾值和初始容量public ConcurrentHashMap(int initialCapacity, float loadFactor) {this(initialCapacity, loadFactor, 1);}//可設(shè)置初始容量和閾值和并發(fā)級(jí)別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 binsinitialCapacity = concurrencyLevel; // as estimated threadslong size = (long)(1.0 + (long)initialCapacity / loadFactor);int cap = (size >= (long)MAXIMUM_CAPACITY) ?MAXIMUM_CAPACITY : tableSizeFor((int)size);this.sizeCtl = cap;}12 ConcurrentHashMap使用什么技術(shù)來保證線程安全?
jdk1.7:Segment+HashEntry來進(jìn)行實(shí)現(xiàn)的;
jdk1.8:放棄了Segment臃腫的設(shè)計(jì),采用Node+CAS+Synchronized來保證線程安全;
13 ConcurrentHashMap的get方法是否要加鎖,為什么?
不需要,get方法采用了unsafe方法,來保證線程安全。
14 ConcurrentHashMap迭代器是強(qiáng)一致性還是弱一致性?HashMap呢?
弱一致性,HashMap強(qiáng)一直性。
ConcurrentHashMap可以支持在迭代過程中,向map添加新元素,而HashMap則拋出了ConcurrentModificationException,因?yàn)镠ashMap包含一個(gè)修改計(jì)數(shù)器,當(dāng)你調(diào)用他的next()方法來獲取下一個(gè)元素時(shí),迭代器將會(huì)用到這個(gè)計(jì)數(shù)器。
15 ConcurrentHashMap1.7和1.8的區(qū)別
jdk1.8的實(shí)現(xiàn)降低鎖的粒度,jdk1.7鎖的粒度是基于Segment的,包含多個(gè)HashEntry,而jdk1.8鎖的粒度就是Node
數(shù)據(jù)結(jié)構(gòu):jdk1.7 Segment+HashEntry;jdk1.8 數(shù)組+鏈表+紅黑樹+CAS+synchronized
總結(jié)
以上是生活随笔為你收集整理的【Java自顶向下】ConcurrentHashMap面试题(2021最新版)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java自顶向下】面试官:HashMa
- 下一篇: 【Java自顶向下】试手小公司,面试官问